home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
database
/
bltp18.zip
/
CZ.HLP
(
.txt
)
< prev
next >
Wrap
CZ Help
|
1994-10-10
|
215KB
|
3,815 lines
CZ_HELP!
INDEX
TUTORIAL_INDEX
LICENSE_AGREEMEN
LICENSE_A
PRODUCT_SUPPORT
STARTING_CZ
USING_CZ
USING_CZ_A
USING_CZ_B
ABOUT_CZ
IS_BULLET
IS_A_DATABASE
IS_DBF
IS_A_BTREE
IS_A_NETWORK
IS_FILE_LOCKING
IS_NLS
DESIGN_A_DB
CREATE_A_DB
ADD_TO_THE_DB
QUERY_THE_DB
UPDATE_THE_DB
DELETE_A_RECORD
PB_COMPILE_WITH
CALL_BULLET
SPECS_OVERALL
SPECS_DBF
SPECS_DBF_A
SPECS_DBF_B
SPECS_DBF_C
SPECS_INDEX
SPECS_INDEX_A
SPECS_INDEX_B
SPECS_INDEX_C
SPECS_MEMORY
SPECS_MEMORY_A
SPECS_OS_CALLS
SPECS_LANGUAGES
SPECS_OSES
SPECS_NETWORKS
SPECS_PERFORMANC
SPECS_PERF_A
SPECS_PERF_B
SPECS_PERF_C
SPECS_PERF_D
INITXB
EXITXB
ATEXITXB
MEMORYXB
BREAKXB
BACKUPFILEXB
STATHANDLEXB
GETEXTERRORXB
DVMONCXB
CREATEDXB
OPENDXB
CLOSEDXB
STATDXB
READDHXB
FLUSHDHXB
COPYDHXB
ZAPDHXB
CREATEKXB
CREATEKXB_A
CREATEKXB_B
CREATEKXB_C
CREATEKXB_D
CREATEKXB_E
CREATEKXB_F
OPENKXB
CLOSEKXB
STATKXB
READKHXB
FLUSHKHXB
COPYKHXB
ZAPKHXB
GETDESCRIPTORXB
GETRECORDXB
ADDRECORDXB
UPDATERECORDXB
DELETERECORDXB
UNDELETERECORDXBwc
PACKRECORDSXB
FIRSTKEYXB
EQUALKEYXB
NEXTKEYXB
PREVKEYXB
LASTKEYXB
STOREKEYXB
DELETEKEYXB
BUILDKEYXB
CURRENTKEYXB
GETFIRSTXB
GETEQUALXB
GETNEXTXB
GETPREVXB
GETLASTXB
INSERTXB
UPDATEXB
REINDEXXB
LOCKXB
UNLOCKXB
LOCKKEYXB
UNLOCKKEYXB
LOCKDATAXB
UNLOCKDATAXB
DRIVEREMOTEXB
FILEREMOTEXB
SETRETRIESXB
DELETEFILEDOS
RENAMEFILEDOS
CREATEFILEDOS
ACCESSFILEDOS
OPENFILEDOS
SEEKFILEDOS
READFILEDOS
EXPANDFILEDOS
WRITEFILEDOS
CLOSEFILEDOS
MAKEDIRDOS
ACCESSPACK
BREAKPACK
COPYPACK
CREATEDATAPACK
CREATEKEYPACK
DESCRIPTORPACK
DOSFILEPACK
DVMONPACK
EXITPACK
FIELDDESCTYPE
HANDLEPACK
INITPACK
MEMORYPACK
OPENPACK
REMOTEPACK
SETRETRIESPACK
STATDATAPACK
STATKEYPACK
STATHANDLEPACK
XERRORPACK
ERRORS_BULLET
ERRORS_BULLET_B
ERRORS_BULLET_C
ERRORS_BULLET_D
ERRORS_BASIC
ERRORS_BASIC_B
ERRORS_DOS
ERRORS_DOS_B
ERRORS_DOS_C
INITXBSRC
EXITXBSRC
ATEXITXBSRC
MEMORYXBSRC
BREAKXBSRC
BACKUPFILEXBSRC
STATHANDLEXBSRC
GETEXTERRORXBSRC
DVMONCXBSRC
CREATEDXBSRC
CREATEDXBSRC_A
OPENDXBSRC
CLOSEDXBSRC
STATDXBSRC
READDHXBSRC
FLUSHDHXBSRC
COPYDHXBSRC
ZAPDHXBSRC
CREATEKXBSRC
CREATEKXBSRC_A
OPENKXBSRC
CLOSEKXBSRC
STATKXBSRC
READKHXBSRC
FLUSHKHXBSRC
COPYKHXBSRC
ZAPKHXBSRC
GETDESCRIPTORXBSz
GETRECORDXBSRC
ADDRECORDXBSRC
UPDATERECORDXBSR
DELETERECORDXBSR
UNDELETERECORDSR_
PACKRECORDSXBSRC1
FIRSTKEYXBSRC
EQUALKEYXBSRC
NEXTKEYXBSRC
PREVKEYXBSRC
LASTKEYXBSRC
STOREKEYXBSRC
DELETEKEYXBSRC
BUILDKEYXBSRC
CURRENTKEYXBSRC
GETFIRSTXBSRC
GETEQUALXBSRC
GETNEXTXBSRC
GETPREVXBSRC
GETLASTXBSRC
INSERTXBSRC
UPDATEXBSRC
REINDEXXBSRC
LOCKXBSRC
UNLOCKXBSRC
LOCKKEYXBSRC
UNLOCKKEYXBSRC
LOCKDATAXBSRC
UNLOCKDATAXBSRC
DRIVEREMOTEXBSRC
FILEREMOTEXBSRC
SETRETRIESXBSRC
DELETEFILEDOSSRC
RENAMEFILEDOSSRC
CREATEFILEDOSSRC
ACCESSFILEDOSSRC
OPENFILEDOSSRC
SEEKFILEDOSSRC
READFILEDOSSRC
EXPANDFILEDOSSRC^,
WRITEFILEDOSSRC
CLOSEFILEDOSSRC
MAKEDIRDOSSRC
~INDEX CZ.HLP-BULLET for PowerBasic 3
System
Mid-level Record/Key Access
InitXB
CreateDXB CreateKXB GetDescriptorXB FirstKeyXB
ExitXB
OpenDXB OpenKXB GetRecordXB EqualKeyXB
AtExitXB
CloseDXB CloseKXB AddRecordXB NextKeyXB
MemoryXB
StatDXB StatKXB UpdateRecordXB PrevKeyXB
BreakXB
ReadDHXB ReadKHXB DeleteRecordXB LastKeyXB
BackupFileXB
FlushDHXB FlushKHXB UndeleteRecordXB StoreKeyXB
StatHandleXB
CopyDHXB CopyKHXB PackRecordsXB DeleteKeyXB
GetExtErrorXB
ZapDHXB ZapKHXB BuildKeyXB
DVmonCXB
CurrentKeyXB
High-level Access
Network
GetFirstXB InsertXB
LockXB UnlockXB LockKeyXB
GetEqualXB UpdateXB
UnlockKeyXB LockDataXB UnlockDataXB
GetNextXB ReindexXB
DriveRemoteXB FileRemoteXB SetRetriesXB
GetPrevXB
GetLastXB
Low-level DOS Access
DeleteFileDOS OpenFileDOS WriteFileDOS
RenameFileDOS SeekFileDOS CloseFileDOS
Move cursor to index item
CreateFileDOS ReadFileDOS MakeDirDOS
and press <Enter>.
AccessFileDOS ExpandFileDOS
See: TUTORIAL_INDEX
~TUTORIAL_INDEX CZ.HLP-BULLET for PowerBasic 3
CZ.COM
Using BULLET
1.08
Starting_CZ
What: How to:
Using_CZ
is_BULLET design_a_DB PB_compile_with
About_CZ
is_a_database create_a_DB
is_DBF add_to_the_DB
is_a_Btree query_the_DB
Error Codes
is_a_network update_the_DB
Errors_BULLET
is_file_locking delete_a_record
call_BULLET
Errors_BASIC
is_NLS
Errors_DOS
LICENSE_AGREEMENT Product_Support
Structure Pack Types
Specifications
AccessPack DVmonPack RemotePack
Specs_Overall
BreakPack ExitPack SetRetriesPack
Specs_DBF
CopyPack FieldDescTYPE StatDataPack
Specs_Index
CreateDataPack HandlePack StatKeyPack
Specs_Memory
CreateKeyPack InitPack StatHandlePack
Specs_OS_Calls
DescriptorPack MemoryPack XErrorPack
Specs_Languages
DOSFilePack OpenPack
Specs_OSes
Specs_Networks
Specs_Performance
See: License_Agreement
~License_Agreement
Before using this software you must agree to the following:
1. You are not allowed to operate more than one (1) copy of this software
package at one time per license. This means that if you have 10 programmers
that COULD possibly use the BULLET library at the same time, you must also
have ten (10) BULLET licenses.
2. You are not allowed to distribute non-executable code containing BULLET
code. This means that you are not allowed to redistribute BULLET code as
another .LIB, for example. Also, if BULLET code is to be contained in a
Dynamic Link Library (DLL) then it must be part of a stand-alone product.
This means that you cannot provide a .DLL containing BULLET code if that
.DLL is to be used as a programming library for other programmers. If you
wish to distribute non-executable code containing BULLET code you must
obtain written permission from the author.
3. This license grants you the right to use the BULLET library code on a
royalty-free basis.
See: License_a -MORE-
~License_a
4. BULLET is owned by the author, Cornel Huth, and is protected by United
States copyright laws and international treaty provisions. You are not
allowed to make copies of this software except for archival purposes.
5. You may not rent or lease BULLET. You may not transfer this license without
the written permission of the author. If this software is an update or
upgrade, you may not sell or give away previous versions.
6. You may not reverse engineer, decompile, or disassemble this software.
7. There are no expressed or implied warranties with this software.
8. All liabilities in the use of this software rest with the user.
9. U.S. Government Restricted Rights. This software is provided with
restricted rights. Use, duplication, or disclosure by the Government is
subject to restrictions as set forth in subparagraph (c)(1)(ii) of the
Rights in Technical Data and Computer Software clause at 52.227-7013.
Manufacturer is Cornel Huth/6402 Ingram Rd/San Antonio, TX 78238.
This agreement is governed by the laws of the state of Texas.
See: Product_Support
~Product_Support
Support is available at my BBS, The 40th Floor, 7 days a week. Hours are
5pm to 9am, Central Time (USA). Weekend BBS hours are 24hrs, starting at
5pm Friday to 9am Monday. Hours other than during above periods are voice.
Central Time is UTC time -5/6 hours, depending on season (UTC=London time).
BBS tele#: 1(210)684-8065 (times listed above)
N81, 300 to 14.4k bps
Latest releases of BULLET are available for free download by registered users.
Also available are other shareware products by me such as LP100, a linear
programming optimizer, and Ruckus, a super-audio programmer's toolkit.
My E-mail address:
Fidonet: 1:387/800.8 (okay)
Internet: cornel@ephsa.sa.tx.us (near term)
cornel@LChance.sa.tx.us (okay)
cornel@crl.com (tentative)
Call the BBS for the latest info and e-mail address, or write.
See: Starting_CZ
~Starting_CZ
At CZ's initial load it looks into the current directory for CZ.HLP, then in
the directory of CZ.COM, and last it looks for the pathname specified by the
DOS variable CZH (SET CZH=C:\DOC\CZ.HLP). Use /f: for alternate locations or
if CZ has any trouble locating its CZ.HLP file (C>cz /f:D:\BIN\CZ.HLP).
Load CZ.COM from the DOS command line. Options are:
/f:helpfile.ext Use other than default CZ.HLP help file
/h# where n=1 to 4 Use alternate hot-key from default Alt-F1
#=1 Ctrl-h
#=2 F12
#=3 left+right Shift
#=4 Alt-left Shift
/u uninstall CZ from memory (after initial load)
/s temporarily put CZ to sleep by restoring all hooked vectors
/r restore CZ from its sleep by rehooking vectors
/? quick help
E.g., C>cz /f:D:\PRG_C\CBULLET.HLP supply entire pathname when using /f:
C>cz /h1 change hot key from Alt-F1 to Ctrl-H
See: Using_CZ
~Using_CZ
To activate CZ press the hot-key while the cursor is on the word you want to
look up. Information on that word, if any, is displayed. If none is available,
an index of help items in the dictionary is shown. Along the top-right of the
index screens is the control bar. You can quickly move to the control bar by
pressing <Home> or the See: line with <End>. Move the cursor to TUTORIAL_INDEX
to select the second index screen or QUIT to return to whatever you were doing
or over any index item. Then press <Enter> to move to that item's help entry.
<F1> can be used as <Enter>. A mouse can also be used and is recommended.
For example, to find out about CreateDXB, type it in your application and move
the cursor on it. Press the hot-key. The CreateDXB screen is displayed. To see
what pack type it uses, move to CreateDataPack (at Pack:) and press <Enter>.
For a source example, move the cursor to Src: CreateDXBsrc. To go straight to
the index from your application, press the hot-key with the cursor on a blank
space. The <Esc> key returns you to your application.
If there are more screens for the current topic the See: line has the same
topic name plus a letter, and -MORE- at the end. Move the cursor (or mouse)
to the topicname text (by using the <End> key) and press <Enter> (or click).
See: Using_CZ_a -MORE-
~Using_CZ_a
CZ.COM can be loaded high but it is ESSENTIAL that you have at least 15K of
free UMB RAM available. It will load in as little as 4.5K but it will not
operate correctly. Use MEM/c to see how much Upper Memory RAM is available.
CZ opens the help file at installation. The help file is opened for Read-Only
access with a Deny None sharing attribute. The file is closed when CZ is
uninstalled (C>cz /u). CZ makes use of its own 256-byte stack.
If you have several CZ help files, rename them to their particular application.
For example:
Rename the QuickBASIC BULLET CZ.HLP to QBULLET.HLP. Put QBULLET.HLP into your
help files directory. Put SET CZH=C:\HELPFILES\QBULLET.HLP in your AUTOEXEC.BAT
file. The next time CZ is installed it uses QBULLET.HLP from C:\HELPFILES.
At anytime you can specify CZ.COM to use another help file. For example, if the
current CZ help file is QBULLET.HLP but you want to use the CBULLET.HLP file,
use C>cz /f:\helpfiles\cbullet.hlp. CBULLET.HLP then becomes the active file
the next time you popup CZ.
See: Using_CZ_b -MORE-
~Using_CZ_b
Limitations (most apply to QB/QBX):
1) The QB environment may interpret the Alt-F1 keypress after CZ has popped
down. If this is a problem then change the hotkey, e.g., C>cz /h2 to use F12.
2) In the QB (and QBX) environment the keypad <Enter> key is not recognized by
CZ. Use the main <Enter>. This occurs only in then QB 4.5 and QBX editors.
3) If, after returning from CZ, the QB environment's menu bar does not respond
to Alt-keys (like an Alt-F), click the left mouse button a few times, or press
F6 to go to the immediate window and execute a SHELL. It's unlikely that you'll
encounter this.
4) CZ is a stable TSR but like all TSRs in a DOS system, unforseen events can
take place that could conceivably cause the computer to crash. Therefore, it's
recommended that you save your work often (you should do so whether a TSR is
installed or not).
5) CZ currently doesn't reset the mouse. If you're having mouse trouble, you'll
need to reset your mouse driver (type MOUSE at the C>). Many problems come from
other programs not restoring the mouse cursor to its original state.
See: About_CZ
~About_CZ
CZ HELP
Context-sensitive Online Help Manager
for the
compiler libraries
MS-DOS PowerBasic version
(available for most DOS compilers)
Copyright 1992-94 Cornel Huth
Ver 1.08 INT2F MuxID=C2 10-Oct-94
See: Specs_Overall
~is_BULLET - What?
BULLET is a program module that handles the details of putting information to
and getting information from your hard disk using a standard data file format
called the Xbase DBF format with very fast and efficient index file routines.
It can be used as-is by most DOS compilers.
BULLET is written in 100% assembly language. Why? Two reasons. First, control.
There's no compiler code or run-time library code in between BULLET and your
data. Second, efficiency. BULLET knows exactly what it requires from the
operating system and when. Result: fast, small, and robust applications.
See: is_a_database
~is_a_database - What?
A database is a collection of data arranged so that the it can be accessed as
useful information. For example, let's say we have two files. Each consists of
two fields. The first file has codenumber and score. The second file has a
codenumber and name. Separately, the files are merely a collection of data.
Together, however, they tie the name to the score:
score codenumber codenumber name
99 100 100 John
87 155 105 Paul
66 125 110 George
: : : :
Codenumber 100 is John, who scored 99. The other members scores are not in the
abbreviated data file listing.
A database can be a single data file but more often it is a group of related
data files and usually these data files are indexed by keys (in the index file,
also called key file) so that very fast, direct access is possible.
See: is_DBF
~is_DBF - What?
DBF is the file extension of dBASE III-compatible data files (filename.DBF).
The file format is used by dBASE IV, FoxPro and many other database programs.
Many programs can also use the file format to import/export data using it.
The DBF format is the most common data file format used on PCs.
A DBF-compatible data file consists 3 distinct areas. First is the data header.
This contains information such as the number of records in the file. Second is
the field descriptors. These descriptors define the makeup of each field in the
record. The third is the record area. Each record is a logical unit of data.
For example, a record, all of which are made up of the same fields but with
different data, could (conceptually) look like this:
field 1 field 2 field 3 field n
record 1
Johnson
Larry
465310555 ...
record 2
Aberdeen
Zara
465230555 ...
record n
See: is_a_Btree Specs_DBF
~is_a_Btree - What?
A b-tree is a sorting method ideally suited to data structures maintained on a
hard disk. It is very fast on retrieval and is inherently self-balancing during
inserts and deletes. Self-balancing ensures performance remains consistent.
The reason the b-tree is ideally suited to hard disks is that, when looking for
a particular key, most of the time involved in accessing the key is spent by
the hard drive moving to various locations on the disk. The task of a good
access method is to reduce the number of seeks that the disk must perform. The
b-tree accomplishes this by maintaining several keys (perhaps 50) on each node,
with the necessary pointers to previous and following nodes. A b-tree of order
20 (19 keys per node) can find a key in a file of 1,000,000 keys in a MAXIMUM
of 5 disk accesses, where each disk access visits a node.
'BASIC program to find *max* seeks needed/avg time
Keys& = 1000000: KeysPerNode = 19: AvgSR = 25
Order = KeysPerNode + 1
max = (LOG((Keys& + 1) / 2) / LOG(Order / 2))
PRINT "Max nodes accessed for"; Keys; "keys & b-tree of order"; Order;
PRINT "is"; max; "nodes"
PRINT "Max disk time based on avg seek+read of"; AvgSR;
PRINT "ms is"; AvgSR / 1000 * max; "seconds"
See: is_a_network Specs_Index
~is_a_network - What?
A network is a group of computers able to communicate with one another. Often
called a LAN (local area network), a network allows resources to be shared.
Sharing resources can lead to problems if steps are not taken to ensure that
two computers don't try to share the same resource at the same time. For
example, say two computers try to change the same record in a file on a network
drive. Let's say both users are accessing the number of widgets in inventory.
The first user gets there a micro-second before the second and allocates the
last widget in stock. The second user comes in right after and, since the first
user has not yet updated the inventory, allocates the very same widget. One
widget, two users. When the first user updates the inventory, widgets in
inventory is changed to 0 (previous - 1). The second updates the inventory in
the same manner and sets widgets to 1 less what it was when it started, or 0
also. You see the problem.
In order to successfully share a file on a network, the file must first be
locked to a single user. Once that user has locked the file, he has sole access
to the data within it and he will not experience the scenario above. When the
user has completed the changes, he unlocks the file so that others may use it.
See: is_file_locking
~is_file_locking - What?
File locking is a means to obtain exclusive access to a file. This is needed in
cases of multiple programs or users accessing a shared file at the same time.
There are several methods to ensure only one process or user has access to a
file. The first method is to open the file so that while the file is open only
your program can access any part of it. This is simple to implement and the
operating system handles the details of this. However, it requires your program
to open/close files all the time since no other process may access the file
while it is open.
Another method is to use byte-level locks. Also managed by the OS, this method
allows for restricting access to any particular region within the file. Which
regions are to be locked is to be determined by your program, however, and it
can be complex to perform multiple locks at the byte, field, or record level.
Another use of the byte-level lock is to specify that all bytes within the file
are to be locked. This greatly simplifies the process of obtaining a lock and
has the advantage over a file access lock of not needing to open/close the file
for each lock. It is very fast and easy to implement. BULLET offers all three
lock types.
See: is_NLS
~is_NLS - What?
NLS stands for National Language Support. This feature is available in DOS 3.3
and later. BULLET makes use of NLS by getting from DOS the current DOS country
collate-sequence table. The collate table is used to properly sort mixed-case
character strings and also foreign (or non-USA) language character strings
according to that country's alphabet. This is an option but is recommended.
In addition, BULLET provides for a programmer-supplied collate-sequence table.
See: design_a_DB
~design_a_DB - How to
To design a database, above all else, know what information you require from
it. Having established what you need to know, collect the data that lets you
formulate this into useful information.
For example, you want to track a class of students and determine how well they
achieve on tests. The criterion you use is the test score. You determine that
your data is 1) students, 2) tests, and 3) test scores. Too simplify, you use
a single 20-character field for student, a 1-character field for test number
("1" to the "n" tests), and a numeric field for test scores (0 to 100).
Since the objective is to track students' scores, arrange the data so that
output consists of each student's score in test order. Do this by specifying an
index file containing an index based on the student's name and test number:
KeyExpression$ = "STUDENT + TEST" 'combine two character fields
This is the reason that field 2, test number, is a character field. It can more
easily be combined with other character fields than a numeric field. By using
the routines of the database langauge, you can easily create the data and index
files, add data, list student's scores, or make changes to the database. Note:
these How_to examples are meant only to show the basis behind an operation.
See: create_a_DB CreateKXB
~create_a_DB - How to
Having defined the database, create it. First, create the datafile based on the
3 fields you defined in your design. To do this, DIM an array for the field
descriptors for the number of fields (see also CreateDataPack):
DIM FD(1 TO 3) AS FieldDescTYPE
FD(1).FieldName = "STUDENT" + STRING$(10,0) 'must be zero-filled
FD(1).FieldType = "C"
FD(1).FieldLength = CHR$(20)
FD(1).FieldDC = CHR$(0)
The FD() is a structure element
FD(2).FieldName = "TEST" + STRING$(10,0)
in CDP (CreateDataPack) as in:
FD(2).FieldType = "C"
CDP.Func=CREATEDXB
FD(2).FieldLength = CHR$(1)
: :
FD(2).FieldDC = CHR$(0)
CDP.FieldListPtrOff=VARPTR(FD(1))
FD(3).FieldName = "SCORE" + STRING$(10,0)
CDP.FieldListPtrSeg=VARSEG(FD(1))
FD(3).FieldType = "N"
: :
FD(3).FieldLength = CHR$(3)
FD(3).FieldDC = CHR$(0)
Call CreateDXB to create the data file. To create the index file, first open
the data file just created, then call CreateKXB to create the index file. Open
the index file so we can use it (data file is already open).
See: add_to_the_DB CreateDXB
~add_to_the_DB - How to
Once you have the database designed and the data and key files created and open
you can start putting the student's test data into it. Note that the DBF-format
requires that all data in a data file be in ASCII format. This means that we
must convert the numeric test score into its ASCII form. BASIC has the STR$()
function to do this. In addition, numbers generally should be right-justified
in their field. BASIC has the RSET statement to do this:
TYPE StudentRecordTYPE 'this structure is exactly how the record is on disk
tag AS STRING * 1 'DBF delete tag used to identify deleted records
sname AS STRING * 20 '--the tag is always present in any DBF record
testn AS STRING * 1 ' don't forget to include it in all your TYPEs
score AS STRING * 3
END TYPE '25
DIM SR AS StudentRecordTYPE
:
INPUT "Student name, test number, score:",n$,t$,s%
SR.sname = n$ : SR.testn = t$ : RSET SR.score = STR$(s%)
status = DoInsert(SR, keyhandle)
LOOP UNTIL LEN(n$) = 0 OR (status <> 0)
See: query_the_DB InsertXB
~query_the_DB - How to
Now that you have data in the database you want to see what's in there. Since
the index file is in "STUDENT + TEST" order, the information we'll be getting
out of the database is in Student name order, with each student's scores in
test number order.
If we want to look at all the students, we can use GetFirstXB to retrieve the
first student's score for the first test. GetNextXB retrieves the next record
(the first student's score for the second test), and so on. When all records
have been retrieve GetNextXB returns an End Of File error code.
If we want to look at a particular student's score only, we can use GetEqualXB
to go directly to a student's first test score. GetNextXB get his next and so
on until GetNextXB retrieves the next student's first test score. You can stop
at this point (student names no longer match).
We might also want to find all students who scored less than 65 on any test. To
do this we can GetFirstXB, check SR.score for < 65 and if so print that record.
Continue by using GetNextXB, printing each record that has a score < 65.
See: update_the_DB GetFirstXB
~update_the_DB - How to
To update a particular record in the database we must first locate and identify
it using one of the get routines such as GetEqualXB. The Get() routine return
the record data, and also the physical record number of the record accessed,
into the AccessPack RecNo. Having used one of the Get() routines to read the
data record from disk to memory, you can make any changes to the data record in
memory. E.g., if a student's score needs to be changed from a 69 to a 96, first
find the record (and its RecNo), then update the score field:
INPUT "Student name, test number",n$,t$
SR.sname = n$ : SR.testn = t$
status = DoGetStudentTestScore(SR, keyhandle, Recno&)
DO UNTIL status <> 200 'student as entered not found, call search routine
status = DoFindStudentTestScore(SR, keyhandle, RecNo&)
LOOP
IF status = 0 THEN
PRINT "Student:" ; SR.sname ; " old score:" ; SR.score
INPUT "Enter new score:"; s% : RSET SR.score = STR$(val(s%))
status = DoUpdateTestScore(SR, keyhandle, Recno&)
ENDIF
Any change to a key field will initiate a key file update automatically.
See: delete_a_record UpdateXB
~delete_a_record - How to
To delete a particular record in the database we must first locate it using
one of the get routines such as GetEqualXB. These Get() routines return the
actual record number of the data record accessed by Get() into the AccessPack
RecNo. Having used one of the Get() routines to find the data record, make a
call to the delete function:
'delete all of Student's records, 1 record for each test he's taken
INPUT "Student name to delete",n$
SR.sname = n$
status = DoGetStudent(SR, keyhandle, RecNo&)
DO UNTIL status <> 200 'student as entered not found, call search routine
status = DoFindStudent(SR, keyhandle,RecNo&)
LOOP
DO
status = DoDeleteRecord(SR, RecNo&) 'does not affect key files
IF status = 0 THEN status = GetNextChkIfSameStudent(SR,keyhandle,RecNo&)
LOOP UNTIL status <> 0
The DeleteRecordXB routine does not physically remove the record from the data
file but instead tags it as being "deleted".
See: PB_compile_with DeleteRecordXB
~PB_compile_with - How to
To create a stand-alone EXE file, compile your BASIC source as required. No
special compiler switches are required. Add the following to the top of your
source files:
DEFINT A-Z
$LINK "PBULLET.PBL"
$INCLUDE "PBULLET.BI"
$LINK "NOATEXIT.OBJ"
See: call_BULLET AtExitXB
~call_BULLET - How to?
BULLET is called through a single entry point. The only argument passed to it
is a segmented far pointer to the control pack. The first two entries in this
pack are the function to be performed and the function return status. BULLET
is a FUNCTION call returning an INTEGER status value.
Each function (or routine) uses a prescribed pack format. For example, some
routines need only know the handle of the file, along with the function number
itself. So, to flush a data file, for example, you would do the following:
DIM HP AS HandlePack 'could also DIM SHARED
HP.Func = %FLUSHDHXB 'FLUSHDHXB is defined as a CONST in PBULLET.BI
HP.Handle = File2FlushHandle 'the handle as returned from the Open() routine
stat = BULLET(HP) 'do the actual call to BULLET
The value of stat is set to the completion code as returned by the FlushDHXB
routine. It is the same as the value returned in HP.Stat *IN ALL BUT A FEW*
cases: InsertXB, UpdateXB, ReindexXB, and LockXB. These routines return not
the actual error code, but rather a transaction index number of the access
that failed. See those routines for more information.
See: is_BULLET FlushDHXB
~Specs_Overall
BULLET is dBASE III/III+/IV .DBF-compatible. This format is compatible with a
large base of software programs including the latest database packages such as
dBASE IV and FoxPro. Spreadsheet packages such as Excel and 1-2-3 can directly
import BULLET DBF data files, too. And because of BULLET's versatility, it can
also create very non-standard data files. This may be a useful feature if data
secrecy is of concern.
BULLET requires MS-DOS 3.30 or above. It uses 19K of code/static data space and
requires at least 40K of workspace. 140K of workspace is ideal.
Overall Specifications:
DBF (per file) INDEX
Max records: 16,777,215 Max nodes: 65,535
Record length: 2-4000 (8192) Max keys: 4,063,170
Max fields: 128 (255) Key length: 1-64
Field length: 1-254 (255) Max key fields: 16
Total open index plus data files can be up to 255. Numbers in () indicate
extended specifications.
See: Specs_DBF
~Specs_DBF
To remain compatible with other dBASE III .DBF platforms you should restrict
your data files to the following specifications:
File ID byte: 3 (83hex if .DBF has memo field, not currently supported)
Max record size: 4000 bytes Max fields/rec: 128 Max field size: 254 bytes
Allowable field name characters: A-Z and the _ (upper-case)
Allowable field types:
C-character, 1-254 bytes
D-date, 8 bytes, in the format YYYYMMDD (19920531)
L-logical, 1 byte, either space, "T" or "Y", "F" or "N"
M-memo, 10 bytes, used as pointer into .DBT file (currently not supported)
N-numeric, 1-19 bytes, ASCII format, uses explicit decimal if needed...
...decimal places may be 0, or 2 to (field size - 3) but no more than 15
Restrict all data in .DBF fields to ASCII. This means you should convert binary
data to the equivalent ASCII representation, e.g., if you have the binary value
22154, it must first be converted to the string "22154" before you can store it
to the .DBF data file. So, while your in-program code deals with binary data,
your I/O code must convert it to/from ASCII. This is a dBASE-compatibility
issue only. If you can forgo these requirements you can use binary fields, any-
character field names, record sizes to 8192 bytes, and up to 255 fields.
See: Specs_DBF_a -MORE-
~Specs_DBF_a
A dBASE III .DBF is composed of 3 sections: the header, the field descriptors,
and the data area.
The header structure (first 32 bytes of file):
Name Type Offset Meaning
FileID byte 0 data file type id, 03 standard (43,63,83,88h)
LastYR byte 1 last update year, binary
LastMo byte 2 last update month, binary
LastDA byte 3 last update day, binary
NoRecs long 4 number of records in file
HdrLen word 8 length of header, including field descriptors, +1
RecLen word 10 length of data record including delete tag
internal byte 12-31 reserved
The last update values are updated to the current date whenever the .DBF file
is flushed or closed. Likewise, the NoRecs value is updated whenever a record
is added to the .DBF. The FileID is specified when you create the file, HdrLen
and RecLen are computed and stored when the file is created, too.
See: Specs_DBF_b -MORE-
~Specs_DBF_b
The field descriptor format (follows header, one per field):
Name Type Offset Meaning
FieldName char 0 field name 10 ASCII characters, A-Z or _ (0-filled)
0T byte 10 field name zero-termintor (must be 0)
FieldType char 11 field type (C D L M N)
internal long 12 reserved
FieldLen byte 16 length of this field
FieldDC byte 17 decimal count
internal byte 18-31 reserved
The unused bytes in the FieldName must be set to zeroes (CHR$(0)).
Each field is described by a 32-byte descriptor. The first field's descriptor
starts right after the header proper, at offset +32. After the last field
descriptor is data byte ASCII 13. (Note: the orginal dBASE III has a 0 byte
following this ASCII 13.) Immediately following this is the actual record data.
See: Specs_DBF_c -MORE-
~Specs_DBF_c
The data record format:
The first record is located at offset HdrLen (from the header). The first byte
of each record is a delete tag. This tag is maintained by the BULLET routines.
A space, ASCII 32, means the record is not deleted; an asterisk, ASCII 42,
means the record has been deleted (marked as deleted, often this is used as a
method to temporarily tag records, for whatever purpose).
Following the tag is the data for each field, not delimited (i.e., the fields
run together without anything separating them). The second record is at offset
HdrLen+reclen. The start offset of any record in the file can be computed as
(recordnumber - 1) * reclen + HdrLen. All data is in ASCII form.
An EOF marker (ASCII 26) is placed at the end of the last record.
See: Specs_Index
~Specs_Index
BULLET uses a proprietary, modified b-tree index method to manage the index
files. The supported key types are:
Type Length Meaning
Character 1-64 ASCII, NLS, or user-supplied sort table
Integer 2 signed or unsigned 16-bit value
Long Int 4 signed or unsigned 32-bit value
In addition to the above types, BULLET allows for unique or duplicate keys in
the index file. If duplicates are allowed, BULLET enumerates each key with an
enumerator word (see FirstKeyXB).
The key may be composed of up to 16 character fields or substrings within those
fields. Numeric fields are considered character fields by BULLET unless the key
is set to binary (see KeyFlags). Integer or LongInt binary keys can be composed
of a single field only. The key expression is specified in text (e.g., "LNAME+
SUBSTR(FNAME,1,1)+MI") and is fully evaluated when the index file is created.
A BULLET index file is composed of 3 sections: the header, the collate-sequence
table, and the node/key entry area.
See: Specs_Index_a -MORE-
~Specs_Index_a
The header structure:
Name Type Offset Meaning
FileID byte 0 index file type id, 20
RootNode word 1 root node number
Keys 24bit 3 number of keys in index file
AvalNode word 6 node number available for reuse
FreeNode word 8 next free node number
KeyLen byte 10 key length
NodeKeys byte 11 number of keys that fit on a node
CodePage word 12 code page ID
CtryCode word 14 country code
internal byte 16-21 reserved
KeyFlags word 22 key flags
KeyExprn byte 24-159 key expression
internal byte 160 reserved
KeyXFlds byte 161 number of fields used by key (1-16)
KeyXlate byte 162-225 translated key expression
internal byte 226-253 reserved
CTsize word 254 collate-sequence table size
See: Specs_Index_b -MORE-
~Specs_Index_b
The collate-sequence table structure:
table byte 256-511 sort weight table of ASCII character 0-255
Node/key entry structure (first entry is in node #1, file offset 512):
2A 0A 00 KEY123 7B 00 00 12 00 KEY178 B2 00 00 0C 00 ...
1. 2. 3. 4. 5. 6. 7. 8. 9.
1. Key count for that node (first byte of each node)
2. 16-bit node back pointer (for non-leaf nodes, 0 if leaf node)
3. First key value, "KEY123" in this case
4. 24-bit data record pointer (low word/hi byte) 7Bh = DBF record number 123
5. 16-bit node forward ptr/back ptr (for non-leaf nodes, 0 if leaf node)
--in this case, it indicates that the key following KEY123 is in node# 12h
--and also that the key before KEY178 is in that node as well
6. Second key (here "KEY178")
7. 24-bit data pointer (record number in DBF)
8. 16-bit forward node pointer (for non-leaf nodes, 0 if leaf node)
9. Repeat 6 to 8 for each key on node. (node size is 512 bytes)
See: Specs_Index_c -MORE-
~Specs_Index_c
As in many b-tree implementations, BULLET's index files maintain an average
load percentage of approximately 66%. This means that in any given node, 66% of
the available space is in use. The free space in the node is attributable to
the constant reshaping of the file as keys are inserted or deleted, causing the
nodes to be split and merged. A split will occur when an insert needs to add a
key to an already full node; a merge will occur when a neighboring node is
small enough to be merged into a just split node. This constant prune-and-graft
of the b-tree results in a node load of about 66% (50% in degenerate cases such
as with already sorted data). It's this aspect of the b-tree that makes it a
consistent performer and a widely-used method of managing index files.
The following formula can be used to determine the number of keys that an index
file can hold:
MaxKeys = MaxNodes * MaxKeysPerNode * LoadFactor
MaxKeys = 65535 * 509/(keylen+5) * .66
The load factor can be increased to ~95% by using the ReindexXB routine. This
load factor results in superior retrieval speeds since there are more keys on
each node. Insertion speed will be decreased, however, since splitting will
occur more frequently, though perhaps not noticeably.
See: Specs_Memory
~Specs_Memory
BULLET allocates memory on an as-needed basis. When linked to an executable
program, BULLET makes use of 17.5K of code space and about 1.5K of static
DGROUP data space. To accomodate the wide variety of compilers, BULLET's API
structure will have the linker included all of the library into your final EXE
program.
All runtime memory allocations are obtained from the operating system. This
means that if your compiler generates code to allocate all the free memory at
startup for its far heap, you need to instruct it to free up some memory for
BULLET's use. In QuickBASIC you can use SETMEM(). You can also use the linker
/CP:n option to limit the amount that the compiler-generated startup code
allocates. The EXEHDR.EXE program can also be used to modify this amount. The
linker /CP: option and the EXEHDR program both modify the EXE header. To
determine if you need to release memory use the MemoryXB routine. It reports
the operating system memory available for use by BULLET.
The amount of memory that BULLET requires is based on which routines are used.
See the next screen for a list of the routines that make malloc calls to the
operating system and how much memory they require.
(Most compilers don't grab all memory as QuickBASIC when it's using $DYNAMIC).
See: Specs_Memory_a MemoryXB -MORE-
~Specs_Memory_a
Routines making dynamic memory allocations and amount (within
16 bytes):
Routine Bytes Basis
InitXB 272 permanent, released when program ends (JFTmode=1)
BackupFileXB 32K temp, released when routine exits
CreateDXB 48+(NF*32) temp, released when routine exits (NF=NoFields)
CreateKXB 544 temp, released when routine exits
OpenDXB 144+((1+NF)*32) semi-permanent, released when file closed
OpenKXB 1264 semi-permanent, released when file closed
PackRecordsXB RL to 64K temp, released when routine exits (RL=RecLength)
ReindexXB 32K to 128K temp, released when routine exits
UpdateXB 2K+RL temp, released when routine exits (RL=RecLength)
For example, when BackupFileXB is called it attempts to allocate 32K from the
OS. If 32K is not available, BackupFileXB returns with an error code of 8 (DOS
error #8, not enough memory). If you won't be using Backup or Reindex, BULLET
can make do with much less memory (use table above).
Needed stack space is 4K (max) for ReindexXB. Other routines can operate with
less than 1K of stack space. In other words, stack use is minimal.
See: Specs_OS_calls
~Specs_OS_calls
BULLET makes use of the following operating system calls:
INT21/25 DOS_setvector INT21/44/0B DOS_setsharingretrycount
INT21/2A DOS_getdate INT21/48 DOS_malloc
INT21/30 DOS_version INT21/49 DOS_free
INT21/35 DOS_getvector INT21/51 DOS_getpsp
INT21/39 DOS_makedir INT21/56 DOS_renamefile
INT21/3D DOS_openfile INT21/59 DOS_getextendederror
INT21/3E DOS_closefile INT21/5A DOS_createtempfile
INT21/3F DOS_readfile INT21/5B DOS_createnewfile
INT21/40 DOS_writefile INT21/5C DOS_lockunlockfile
INT21/41 DOS_deletefile INT21/65/01 DOS_getextendedcountryinfo
INT21/42 DOS_movefileptr INT21/65/06 DOS_getcollatesequencetable
INT21/44/09 DOS_isdriveremote INT21/67 DOS_sethandlecount
INT21/44/0A DOS_isfileremote INT2F/10/00 DOS_isshareinstalled
No other operating system calls are made. No BIOS calls are made.
See: Specs_Languages
~Specs_Languages
BULLET is compatible with most DOS compilers. The only requirements are that
your compiler allow you to:
1. Call a library routine via a FAR call using PASCAL calling convention
2. Pass a far pointer (of the parameter pack) on the stack, by value
3. Supply far pointers to the various pack parameters
4. Be able to return an integer value from the FAR call
(this is optional but recommended for the transaction-based routines)
These requirements can be met with most BASIC, C, and other-language DOS
compilers.
CZ online help is currently available in BASIC and C versions. Others are
pending. You should be able to do well with either of these versions using
other-language compilers since the only difference is the source code examples.
See: Specs_OSes
~Specs_OSes
BULLET is currently available only for MS-DOS and compatible operating systems.
It requires DOS 3.3 or higher.
To provide efficient memory use, BULLET uses a single-buffer cache per index
file. The single-buffer cache also provides for very quick network access since
a minimum amount of memory needs to be flushed when releasing control of BULLET
files. For maximum speed, however, an external high-performance disk cache can
be used. Hyperdisk is a good choice (shareware, $50+). A properly configured
cache can increase BULLET's performance from 10 to 300%. The most improvement
is with the InsertXB routine. The least is with ReindexXB and PackRecordsXB,
which do most of their work in temporarily allocated memory. Hyperdisk is about
the best designed disk cache available for PCs. SmartDRV 4.x is also good.
If you do not use a disk cache then it's recommended that you set your BUFFERS=
statement in CONFIG.SYS to at least 20 or 30. Even without a disk cache, BULLET
is still very fast. Also, be sure to set your FILES= to the number of files
that you'll be opening at any one time. If you set FILES=20 you can have BULLET
open 14 files (CZ.COM uses 1 and DOS reserves 5 more). You can set FILES=255
allowing BULLET to open up to 249 files at one time.
DO NOT set FILES= to a value greater than 255.
See: Specs_Networks
~Specs_Networks
BULLET currently operates on all DOS-compatible network platforms.
Be sure to install SHARE.EXE (or compatible) on the server and, if you are
mutlitasking, on your local machine. If you'll be opening many files you
should extended the default SHARE file-sharing information space and the number
of locks that can performed at one time. The DOS 5.0 default is /F:2048 and
/L:20. This allocates 2K for file-sharing info space and allows 20 consecutive
locks to be active. If the F: value is too low, error 5 (extended error 32) is
returned on an open attempt. If you extend the JFT in InitXB and plan to use
many files, say more than 50, be sure to extend /F: by 2K for every 50
additional files and set the /L: to the number of files you plan on having
open. If L: is too low, error 1 (ext err 36) is returned on a lock attempt.
As an example, if you'll be using 100 files, set FILES=106 in CONFIG.SYS, set
SHARE /F:4096 /L:106, and IP.JFTmode=1 for InitXB. These values are a minimum.
If you have more than one process active, you need to account for other apps.
Note that Windows always returns a "SHARE is installed" using the DOS detection
routines used by BULLET. To determine if SHARE is actually installed, attempt
to perform a lock using one of the LockXB routines. An error code indicates
that SHARE (or compatible) is not installed.
See: Specs_Performance
~Specs_Performance
Test: Reindex 1,000 to 1,000,000 records (BB_LAI10.BAS)
DBF: extended DBF using binary sort field
key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
1Meg
*
*
Records Time Reindex Rate
* ------- ---- ------------
100k
* 1000 < 1 1000+/sec
5000 2 2500
* 10000 4 2500
* 25000 7 3571 3500+ records indexed/second!
50000 14 3571 Times in table are in seconds
10k
* 100000 28 3571
200000 81 2469
* 500000 355 1408
1000000 1124 890
1k
time (secs) 100 200 300 400 18:00 20:00 (min)
See: Specs_Perf_a -MORE-
~Specs_Perf_a
Test: Add 1,000 to 1,000,000 records (BB_LAI10.BAS)
DBF: extended DBF using binary sort field
key: not indexed Machine: 486/33 SHO
1Meg
*
*
* Records Time Add Rate
------- ---- ------------
100k
* 1000 < 1 1000+/sec
5000 2 2500
* 10000 4 2500
* 25000 12 2083 2000+ records added/second!
50000 24 2083 Times in table are in seconds
10k
* 100000 50 2000
200000 103 1942
* 500000 262 1908
1000000 529 1890
1k
time (secs) 100 200 300 400 8:00 10:00 (min)
See: Specs_Perf_b -MORE-
~Specs_Perf_b
Test: Access 1,000 to 1,000,000 keys(*), keys+records(+) (BB_LGK10.BAS)
DBF: extended DBF using binary sort field
key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
1Meg
* +
* +
* + Keys Time Access Rate Keys+Recs Time Access Rate
------- ---- ----------- --------- ---- ------------
100k
* + 1000 < 1 1000+/sec 1000 < 1 1000+/sec
10000 1 10000 10000 6 1667
100000 22 4545 100000 68 1471
200000 49 4082 200000 144 1389
500000 147 3401 500000 427 1171
10k
*+ 1000000 424 2358 1000000 948 1055
Times for forward/reverse (Next/Prev) were similar (
+ Times in table are in seconds
1k
time (secs) 100 200 300 400 15:00 17:00 (min)
See: Specs_Perf_c -MORE-
~Specs_Perf_c
Test: Insert 1,000 random records to existing data/key files (BB_LAA10.BAS)
DBF: extended DBF using binary sort field
key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
Base records/keys Inserted Time / Rate
----------------- -------- ---- ----
1000 1000 15 67 records+keys inserted/second
10000 1000 18 56 Times in table are in seconds
100000 1000 19 53
200000 1000 20 50
This tests the InsertXB speed. A data file containing the base records and
an index file containing the same number of keys has inserted into it 1000
random keys and records. The records are added to the end of the data file
and the keys are inserted into their appropriate place in the index file.
Typically InsertXBs would be done online. The rate of 50 inserts/second at
200,000 records would indicate a time of 0.02 seconds per insert on even a
very large database (0.015 secs/insert @ 1000 records).
See: Specs_Perf_d -MORE-
~Specs_Perf_d
Test: Update 1,000 records by changing the key field (BB_LAU10.BAS)
DBF: extended DBF using binary sort field
key: LONG+SIGNED+UNIQUE Machine: 486/33 SHO
Base records/keys Updated Time / Rate
----------------- ------- ---- ----
1000 1000 50 20 records+keys updated/second
10000 1000 59 17 Times in table are in seconds
100000 1000 108 9
200000 1000 126 8
This tests the UpdateXB speed. A data file containing the base records and
an index file containing the same number of keys has the first 1000 keys and
records changed. This forces the old data record to be replaced, the old index
key to be deleted, and a new key for the record to be inserted in the index
file.
Typically UpdateXBs would be done online. The rate of 8 updates/second at
200,000 records would indicate a time of 0.125 seconds per update on even a
very large database (0.05 secs/update @ 1000 records).
See: Specs_Overall
~InitXB
Pack: InitPack Src: InitXBsrc Func: 0/System
Before using any routine you must initialize the BULLET file system.
If you want more than the standard number of file handles, set InitPack.JFTmode
to 1. This expands the current process's Job File Table to allow 255 open files
maximum.
On return the DOS version (INT21/30h) is in InitPack.DOSver. Major version in
the high byte. Minor in the low. The BULLET version (*100) is returned as is
the address of the ExitXB routine. You can use this address to register ExitXB
with your own _atexit function if your runtime library does not provide _atexit
already.
Note: _atexit is a routine available in most DOS, OS/2, and ANSI runtime
library code and is called just prior to the program ending. See AtExitXB for
information on what to do if your library does not have _atexit.
See: ExitXB
~ExitXB
Pack: ExitPack Src: ExitXBsrc Func: 1/System
Before ending your program you should call ExitXB to close any open BULLET
files. This also will release any memory still allocated to those files.
This restores the default keyboard break handlers if they were changed.
In normal operation you would see to closing all files yourself. However, if
your program fails to reach the programmed end, it's very possible that files
may still be left open. It is essential that you properly close all BULLET
files before ending. There are two methods to achieve this:
1. In BASIC use ON ERROR GOTO label, where label is in the main module. The
code at label would then call ExitXB.
2. Use AtExitXB to automatically register ExitXB to be executed in the normal
shut-down code of the compiler. This method is preferred.
In the QB environment you can easily stop and restart the executing program
without having reached the end of the program where you call ExitXB. Previously
opened BULLET files remain open and memory used remains allocated. Eventually
you will run out of files or out of memory. Use AtExitXB to prevent this.
See: AtExitXB
~AtExitXB
Pack: ExitPack Src: AtExitXBsrc Func: 2/System
Used to automatically close all BULLET files, release allocated memory, and
restore the default Break handlers when your program ends. Your compiler
generates specific code to be executed in the course of ending your program.
AtExitXB registers the ExitXB routine to be performed in this compiler-
generated code.
This routine is standard in most DOS, OS/2, and ANSI runtime libraries. If
yours does not have _atexit, then you must link with the supplied
NOATEXIT.OBJ file:
C>link YOURPRG + NOATEXIT, ...
You can tell if your compiler doesn't supply _atexit at link time. LINK reports
'_atexit' : unresolved external. Add NOATEXIT.OBJ as described above.
Be sure that your _atexit routine is for the medium, large, or huge memory
models since BULLET uses multiple code segments and far calls.
See: MemoryXB ExitXB BreakXB
~MemoryXB
Pack: MemoryPack Src: MemoryXBsrc Func: 3/System
This is the only BULLET routine that can be used before InitXB. It reports the
largest free block of memory available from the OS. This memory does not
include fragmented memory or UMB memory that BULLET can and will use.
Some compilers provide their own memory management and thus will use most or
all of the contiguous memory when its program loads. BULLET, however,
allocates memory on an as-needed basis, directly from the OS, and releases it
back to the OS as soon as it is no longer needed. If the memory amount
returned by MemoryXB is low, your compiler's startup code has pre-allocated
all OS memory. If the memory available from the OS is less than your
application needs, you need to instruct your program to release some of the
memory back to the OS so BULLET can use it. For QuickBASIC and BASIC PDS, see
the BASIC function SETMEM().
With DOS able to use UMB memory, memory for BULLET requests may be provided
from this region. You can use StatPack.HereSeg from StatXB to locate from which
segment address the allocations are being made. Anything above C800h is UMB.
See: BreakXB StatXB OpenDXB OpenKXB
~BreakXB
Pack: BreakPack Src: BreakXBsrc Func: 4/System
Disables system response to Control-C and Control-Break keys preventing users
from inadvertently exiting the program without first doing a BULLET shutdown.
It's REQUIRED that you reinstate the default break handlers with this routine
before ending your program. ExitXB automatically reinstates the default break
handlers.
This routine will not disable Control-Alt-Delete (a warm-boot). If the user is
at this point, he may prefer to exit via a warm-boot rather than reset the
machine.
Also, this routine does not prevent QuickBASIC and BASIC PDS from terminating
a program at an INPUT statement. This is because these versions of BASIC are
using their own method of INPUT aside from DOS. If AtExitXB has been issued,
all BULLET files will be properly closed even if *User Break* occurs.
This routine will not surpress the ^C displayed by DOS. If you don't want the
^C to be displayed move the cursor to a location off-screen, say, row 26.
See: BackupFileXB ExitXB
~BackupFileXB
Pack: CopyPack Src: BackupFileXBsrc Func: 5/System
Copy an open BULLET key or data file. BULLET repacks and reindexes files in-
place, requiring less disk space to perform the function. BackupFileXB allows
you to safely copy a file before doing this.
This function is recommended prior to packing a data file with PackRecordsXB
since the data is very valuable. There is probably little need to do so when
reindexing an index file since index files can be constructed very easily
from the data file.
See: StatHandleXB PackRecordsXB ReindexXB
~StatHandleXB
Pack: StatHandlePack Src: StatHandleXBsrc Func: 6/System
Get information on a DOS file handle number to determine if it is a BULLET file
and if so, if that file is a BULLET key or data file.
If the returned ID value is 0, the handle is to a BULLET index file. ID=1 then
the handle is a BULLET .DBF file. ID= -1 then the handle is not a BULLET file.
See: CreateDXB StatDXB StatKXB
~GetExtErrorXB
Pack: XErrorPack Src: GetExtErrorXBsrc Func: 7/System
Get the extended error information for the last operation. This information
includes the extended error code, the error class, the recommended action, and
the location of the error. See Errors_DOS for the extended error meaning an
Errors_DOS_c for the class, action, and locus code meanings.
Note that on fatal DOS errors, such as an open floppy drive door, the extended
error code returned is 83 - fail on INT24. This indicates that the INT24
handler was invoked by DOS and that the INT24 handler told DOS to ignore the
error. (BULLET invokes its own INT24 handler each time it accesses the DOS file
system and restores it promptly after the access.) In such cases, this extended
error code is less informative than the standard return code and, the other
'extended' information should be disregarded. (In fatal DOS errors the standard
return code IS the extended error code.)
This routine returns the extended error information for the LAST DOS system
error. This information remains the same until the next DOS system error.
See: CreateDXB Errors_DOS
~DVmonCXB
Pack: DVmonPack Src: DVmonCXBsrc Func: 9/DEBUG
Control BULLET debug monitor.
This routine is available only in the debug engine.
The monitor displays in realtime the state of a data file handle, or an index
and data file handle pair if an index handle is specified. DVmonCXB is best
used on dual-display systems in which the video output is sent to the secondary
video monitor. In any case, a 4000-byte screen image is updated in real-time.
To use the monitor, set mode=1, handle=file to monitor, and VideoSeg=segment
address of 4000-byte area. The typical VideoSeg would be to video memory. If
you have a color system as the main monitor and a mono as the secondary, set
VideoSeg=&HB000. Detail system stats are continually updated to the secondary
monitor. If you have a single monitor with at least 2 video pages, set VideoSeg
to your base address plus the page size\16, typically &HB800+(4096\16). If you
have only a single-page video system, you can allocate a 4000-byte memory area
and update the video manually by moving it to your video display (80x25).
See: CreateDXB StatDXB StatKXB
~CreateDXB
Pack: CreateDataPack Src: CreateDXBsrc Func: 10/Mid-level
Create a new BULLET .DBF data file. Before using this routine allocate a field
description array of TYPE FieldDescTYPE for at least as many fields as are in
the record.
Conventional dBASE .DBF files have a FileID=3. Other possible FileIDs that you
may come across are (in hex):
43h \__ are special-use Xbase IV DBF files, BULLET can process these file IDs
63h / since they are similar to ID type 3
83h --- this DBF file has an Xbase III/III+ memo field/file
88h --- this DBF file has an Xbase IV memo field/file
In creating your .DBF files, specify FileID=3 to ensure compatibility across
Xbase versions.
BULLET makes no special use of the FileID byte.
See: OpenDXB FieldDescTYPE CreateKXB
~OpenDXB
Pack: OpenPack Src: OpenDXBsrc Func: 11/Mid-level
Open an existing .DBF data file for use. You need to specify two things, the
filename and the DOS file access mode. If the open succeeds, the DOS file
handle is returned. Use this handle for all further access to this file.
Each .DBF data file you open allocates 144+((1 + number of fields) * 32) bytes
for internal use. This memory is not deallocated until you close the file with
CloseDXB or execute ExitXB.
You must open the data file before you can open (or create) any of its index
files.
See: CloseDXB OpenKXB
~CloseDXB
Pack: HandlePack Src: CloseDXBsrc Func: 12/Mid-level
Close an existing .DBF data file for use. Closing the file updates the file
header and deallocates the memory used by this file.
You MUST close all BULLET files before ending your program or file corruption
may occur. To ensure that all files are closed in the event of an unscheduled
program termination, use AtExitXB.
See: StatDXB ExitXB CloseKXB
~StatDXB
Pack: StatDataPack Src: StatDXBsrc Func: 13/Mid-level
Get basic information on the BULLET .DBF data file handle specified.
Information returned includes the number of records in the file, the record
length, number of fields per record, and the date the file was last updated.
Typically, your program will keep track of whether a particular handle belongs
to a data file or a key file. In cases where this is not possible, call the
StatHandleXB routine to determine what file type a handle is.
Note that a just-created data file will have the LastUpdate date set to 0/0/0.
See: ReadDHXB StatKXB StatHandleXB
~ReadDHXB
Pack: HandlePack Src: ReadDHXBsrc Func: 14/Mid-level
Reload the disk copy of the data header for the opened .DBF data file handle
to the internal copy.
In single-user, single-tasking systems this routine is not needed. However, in
a multi-user or multi-tasking system it's possible, and desirable, for two or
more programs to use the same data file. Consider this scenario: A data file
has 100 records. Two programs access this data file, both opening it. Program 1
locks the file, adds a new record, then flushes and unlocks the file. Program 1
knows that there are now 101 records in the file. However, Program 2 is not
aware of the changes that Program 1 made--it thinks that there are still 100
records in the file. This out-of-sync situation is easily remedied by having
Program 2 reload the data header from the file on disk.
How does Program 2 know that it needs to reload the header? It doesn't. Instead
BULLET uses a simple yet effective approach when dealing with such problems.
Whenever your program locks a file, BULLET automatically reloads the header.
Whenever you unlock a file, BULLET automatically flushes the header.
See: FlushDHXB ReadKHXB LockXB
~FlushDHXB
Pack: HandlePack Src: FlushDHXBsrc Func: 15/Mid-level
Write the internal copy of the data header for the opened .DBF data file handle
to disk. The actual write occurs only if the header has been changed.
This is to ensure that the data header on disk matches exactly the data header
that is being maintained by BULLET. Also, this routine updates the operating
system's directory entry for this file.
Assume the following: A data file with 100 records. Your program opens the data
file and adds 1 record. Physically, there are 101 records on disk. However, the
header image of the data file on disk still reads 100 records. This isn't a
problem, BULLET uses its internal copy of the data header and the internal copy
does read 101 records. BUT, if there were a system failure now, the disk image
would not get updated. After the system restart, BULLET opens the file, reads
the header and thinks that there are 100 records. You lost a record. Now, if
after that add above, your program issued a FlushDHXB, the header on disk is
refreshed with the internal copy, keeping the two in-sync. Also, the routine
updates the DOS directory entry, keeping things neat there as well. Still, it
doesn't come without cost: flushing will take additional time, therefore, you
may elect to flush periodically, or whenever the system is idle.
See: CopyDHXB ReadDHXB FlushKHXB LockXB
~CopyDHXB
Pack: CopyPack Src: CopyDHXBsrc Func: 16/Mid-level
Copy the .DBF file structure of an open data file to another DOS file.
This routine makes it easy for you to duplicate the structure of an existing
.DBF file without having to specify all the information needed by CreateDXB.
The resultant .DBF will be exactly like the source, including number of fields
and field descriptions. It will contain 0 records.
See: ZapDHXB CopyKHXB
~ZapDHXB
Pack: HandlePack Src: ZapDHXBsrc Func: 17/Mid-level
Delete all records for a .DBF data file.
This routine is similar to CopyDHXB except for one major difference: ALL DATA
RECORDS IN THE *SOURCE* FILE ARE PHYSICALLY DELETED, so be *careful*.
If you have a .DBF file with 100 records and use ZapDHXB on it, all 100 records
will be physically deleted and the file truncated to 0 records. There is no
return from this routine. All data is gone.
* C A U T I O N *
See: CreateKXB CopyDHXB ZapKHXB
~CreateKXB
Pack: CreateKeyPack Src: CreateKXBsrc Func: 20/Mid-level
Create a new BULLET key file. Before you can create a key file, you must first
have opened (and have created if necessary) the BULLET .DBF data file that it
is to index. (BULLET couples index and data files tightly.)
To create the key file, you need to provide the key expression, key flags, .DBF
file link handle, and optionally, the code page ID, country code, and collate
table.
Key Expression
The key expression is an ASCII character string composed of the elements that
are to make up this index file's key. The key can be composed of any or all of
the fields in the .DBF data record or sub-strings within any of those fields.
Two functions are supported in evaluating a key expression. These are SUBSTR()
and UPPER(). SUBSTR() is similar to BASIC's MID$() in that it extracts part of
a string starting at a particular position for x number of characters. UPPER()
is similar to UCASE$() in that it converts all lower-case letters to their
upper-case equivalent. Since BULLET supports NLS, UPPER() conversion is not
required for proper sorting of mixed-case text strings.
See: CreateKXB_a CreateDXB -MORE-
~CreateKXB_a
All names used in the key expression must be a valid field name in the DBF data
file. Some sample key expressions given that the .DBF has the following fields:
Fields... Valid key expressions
FNAME C 25 0 kx = "LNAME"
LNAME C 25 0 kx = "LNAME+FNAME"
SSN C 9 0 kx = "SUBSTR(LNAME,1,4)+SUBSTR(FNAME,1,1)+SUBSTR(SSN,6,4)
DEPT N 5 0 kx = "UPPER(LNAME+FNAME)" (for non-NLS index files)
: : kx = "DEPT+SSN" (N- + C-type is valid for non-binary keys)
Key Flags
The key expression is used in conjunction with the key flags to determine the
type of key generated.
First, if your index file is to disallow duplicate keys, add 1 to KeyFlag.
If you have a key composed of a character field(s) or portions thereof, you
specify a KeyFlag = 2. This instructs BULLET that the sort order is left-to-
right (proper mixed-case sorting is available, see code page ID).
See: CreateKXB_b -MORE-
~CreateKXB_b
If you have a key composed of a numeric field(s) or portions thereof, you can
also specify a KeyFlag = 2. This instructs BULLET to treat the numeric field
as a regular character field for sorting. To ensure proper sorting, you must
decimal-align the +numeric strings in the .DBF data field, i.e., right-justify
the numeric strings (dBASE .DBF numeric strings are stored as ASCII strings).
These non-binary numeric fields are just like character fields to BULLET.
In addition, if you have a key composed of a SINGLE numeric field (fld type N)
and the field is an integer (NO DECIMAL POINT), you can specify a KeyFlag of 16
or 32. KeyFlag=16 is for a field known to be in word/integer range; KeyFlag=32
if the field is known to be in LongInt range. These KeyFlag values instruct
BULLET to sort the key as a 16/32-bit BINARY value. It also stores the key as a
16- or 32-bit value (only 2 or 4 bytes) in the index, eventhough the data field
is in ASCII (keyflag=16 or 32).
Although not dBASE compatible, you may use BINARY FIELDS in your data records.
dBASE always has ASCII data in the data fields, even if the field is numeric.
For example, an N type field of 8.2 is stored as an ASCII text string in the
data record, say, a string like " 1100.55". If you want dBASE compatibility
your field data must also be ASCII. However, if you can forgo this requirement,
you can use binary values in the fields.
See: CreateKXB_c -MORE-
~CreateKXB_c
To do this you must specify a field type of "B" (actually, anything but a "N")
and, IF IT IS TO BE USED AS A KEY FIELD, also set the 16- or 32-bit KeyFlag.
Unique and signed may also be flagged. The field length for a "B" field type is
2 or 4. Make sure the key flags match (2 if cINTEGER, 4 if cLONG).
If you specify a binary key flag (for either N or B field types), you must also
specify whether the field is to be treated as a signed or unsigned value. If
values less than 0 are possible, add to KeyFlag the hex number &H8000.
KeyFlag = %cUNIQUE + %cCHAR 'unique character key (NLS sort)
KeyFlag = %cINTEGER + %cUNIQUE 'unique unsigned integer (binary sort)
KeyFlag = %cUNIQUE + %cSIGNED + %cLONG 'unique signed long
KeyFlag = %cCHAR 'character key with duplicates allowed
KeyFlag = %cCHAR + %cINTEGER 'THIS IS AN INVALID KEY FLAGS!
KeyFlag = %cLONG 'unsigned long (dups allowed)
The following values are defined in PBULLET.BI:
cUNIQUE=1, cCHAR=2, cINTEGER=&H10, cLONG=&H20, cNLS=&H4000, cSIGNED=&H8000
The NLS flag is assigned by BULLET. StatKXB is used to query KeyFlags.
See: CreateKXB_d -MORE-
~CreateKXB_d
The key expression you specify may be up to 136 characters, and evaluate out to
64 bytes (62 bytes if unique key is not specified). I.e, kx$ = "SUBSTR(..." can
be up to 136 characters, and that the actual key built from this expression can
be no longer that 64 bytes, or 62 if you did not specify UNIQUE. In general,
shorter keys (the key itself, not the expression) offer better performance.
DBF File Link Handle (XBlink)
Since BULLET evaluates the key expression at CreateKXB, it must have access to
the DBF file to verify that the key expression is valid. You must therefore
supply CreateKXB with the OS file handle of the opened DBF data file.
National Language Support (NLS)
With DOS 3.3 and later, NLS is available. BULLET uses NLS to build the collate
sequence table that it uses to ensure proper sorting of mixed-case keys as well
as the sorting of foreign language alphabets. In order for BULLET to use the
proper collate table, it must know what code page ID and coutry code to use.
This table is made part of the index file so that all subsequent access to the
index file maintains the original sort order, even if the MIS shop is moved to
another location/computer system using another country code/code page.
See: CreateKXB_e -MORE-
~CreateKXB_e
Code Page ID
To use the default code page ID of the computer in use, specify a code page ID
of -1. This instructs BULLET to use the collate-sequence table as provided by
MS-DOS running on the machine. You may also specify the code page ID for BULLET
to use, but only if support for the code page ID is available on your machine.
Look in your DOS manual under CUSTOMIZING FOR INTERNATIONAL USE for specific
code page IDs and country codes. See also the COUNTRY and NLSFUNC commands.
You may also specify a code page ID = 0 in which case no collate table is used.
Country Code
To use the default country code of the computer in use, specify a country code
of -1. This instructs BULLET to use the collate-sequence table as provided by
MS-DOS running on the machine. You may also specify the country code for BULLET
to use, but only if support for the country code is available on your machine.
Look in your DOS manual under CUSTOMIZING FOR INTERNATIONAL USE for specific
code page IDs and country codes. See also the COUNTRY and NLSFUNC commands.
You may also specify a country code = 0 in which case no collate table is used.
Typically, you set CodePageID = -1, CoutryCode = -1 and CollatePtr = 0.
See: CreateKXB_f -MORE-
~CreateKXB_f
User-specified Collate Table
If you are to use a MS-DOS supplied collate table (BOTH codepage ID and country
codes are non-zero) then you do not need to specify a collate table--DOS will.
The option to allow a user-specified collate table is to work around some DOS
versions supplying incorrect collate tables. If you find that the DOS-supplied
collate table is not valid (it's stored in the second sector of the file) for
your country, you can supply the table to be used by pointing the CollatePtr
variables to your in-memory version of a valid collate table. If you want to
use the DOS-supplied collate table, you MUST set the CollatePtr variables = 0.
Note: The collate table is a 256-byte table that contains the sort value of
each character (0-255). For example, the first byte would be 0, second would
be 1, and so on. Values for characters up to the lower-case letters (ASCII 97)
are usually as you would expect: "A" has a value of 65. However, the lower-case
letters have the same value as their upper-case counterparts: "a" also has a
value of 65. BULLET uses this collate table to ensure proper sorting.
If you specify EITHER code page ID OR country code = 0 then no collate table
is used or built. Instead, sorting is done by standard ASCII sort. This is
somewhat faster but less versatile. Use UPPER() for mixed-case sort if needed.
See: OpenKXB CreateKXB
~OpenKXB
Pack: OpenPack Src: OpenKXBsrc Func: 21/Mid-level
Open an existing key file for use.
Each key file that you open allocates 1264 bytes for internal use. This memory
is not deallocated until you close the file with CloseKXB or execute ExitXB.
You must open the data file before you can open its related index file
because you must supply the handle of the data file that this index files
indexes.
See: CloseKXB OpenDXB
~CloseKXB
Pack: HandlePack Src: CloseKXBsrc Func: 22/Mid-level
Close an open key file. Closing the file updates the file header and
deallocates the memory used by this file.
You MUST close all BULLET files before ending your program or file corruption
may occur. To ensure that all files are closed on the event of an unscheduled
program termination, use AtExitXB.
See: StatKXB ExitXB CloseDXB
~StatKXB
Pack: StatKeyPack Src: StatKXBsrc Func: 23/Mid-level
Get basic information on a BULLET key file handle specified. Information
returned includes the number of keys in the file, the key length, the data file
handle for this key, the last accessed record number of that data file, NLS
information, and the key flags.
Typically, your program will keep track of whether a particular handle belongs
to a key file or a data file. In cases where this is not possible, call the
StatHandleXB routine to determine what file type a handle is.
See: ReadKHXB StatDXB StatHandleXB
~ReadKHXB
Pack: HandlePack Src: ReadKHXBsrc Func: 24/Mid-level
Reload the disk copy of the key header for the opened key file handle to the
internal copy.
In single-user, single-tasking systems this routine is not needed. However, in
a multi-user or multi-tasking system it's possible, and desirable, for two or
more programs to use the same data file. Consider this scenario: A key file has
100 keys. Two programs access this key file, both opening it. Program 1 locks
the file, adds a new key, then flushes and unlocks the file. Program 1 knows
that there are now 101 keys in the file. However, Program 2 is not aware of the
changes that Program 1 made--it thinks that there are still 100 keys in the
file. This out-of-sync situation is easily remedied by having Program 2 reload
the key header from the file on disk.
How does Program 2 know that it needs to reload the header? It doesn't. Instead
BULLET uses a simple yet effective approach when dealing with such problems.
Whenever your program locks a file, BULLET automatically reloads the header.
Whenever you unlock a file, BULLET automatically flushes the header.
See: FlushKHXB ReadDHXB FlushDHXB LockXB
~FlushKHXB
Pack: HandlePack Src: FlushKHXBsrc Func: 25/Mid-level
Write the internal copy of the key header for the opened key file handle to
disk. The actual write occurs only if the header has been changed.
This is to ensure that the key header on disk matches exactly the key header
that is being maintained by BULLET. Also, this routine updates the operating
system's directory entry for this file.
Assume the following: A data file with 100 keys. Your program opens the key
file and adds 1 key. Physically, there are 101 keys on disk. However, the
header image of the data file on disk still reads 100 keys. This isn't a
problem, BULLET uses its internal copy of the key header and the internal copy
does read 101 keys. BUT, if there were a system failure now, the disk image
would not get updated. After the system restart, BULLET opens the file, reads
the header and thinks that there are 100 keys. You lost a key. Now, if after
that add above, your program issued a FlushKHXB, the header on disk is
refreshed with the internal copy, keeping the two in-sync. Also, the routine
updates the DOS directory entry, keeping things neat there as well. Still, it
doesn't come without cost: flushing will take additional time, therefore, you
may elect to flush periodically, or whenever the system is idle.
See: CopyKHXB ReadKHXB FlushDHXB LockXB
~CopyKHXB
Pack: CopyPack Src: CopyKHXBsrc Func: 26/Mid-level
Copy the key file structure of an open key file to another DOS file.
This routine makes it easy for you to duplicate the structure of an existing
key file without having to specify all the information needed by CreateKXB.
The resultant key file will be exactly like the source, including key flags and
key expression. It will contain 0 keys.
See: ZapKHXB CopyKHXB
~ZapKHXB
Pack: HandlePack Src: ZapKHXBsrc Func: 27/Mid-level
Delete all keys for a key file.
This routine is similar to CopyKHXB except for one major difference: ALL KEYS
IN THE *SOURCE* FILE ARE PHYSICALLY DELETED, so be *careful*.
If you have a key file with 100 keys and use ZapKHXB on it, all 100 keys will
be physically deleted and the file truncated to 0 keys. There is no return from
this routine. All data is gone.
* C A U T I O N *
See: GetDescriptorXB CopyKHXB ZapDHXB
~GetDescriptorXB
Pack: DescriptorPack Src: GetDescriptorXBsrc Func: 30/Mid-level
Get the field descriptor information for a field.
You can specifiy either the fieldname or the field number (position of the
field within the record where the first field is #1) to get info on.
The field descriptor contains the following information:
FIELDNAME 10 upper-case characters, A-Z and _ allowed, unused space is
0-filled and is 0-terminated (11 bytes, ASCII, byte 11 always=0)
FIELDTYPE single ASCII character where C=character, N=numeric, D=date,
L=logical, and M=memo field (1 byte, ASCII)
FIELDLEN length of field: C=1-254, N=1-19, D=8 (yyyymmdd), L=1 (T/F/space),
M=10, this is total field length (1 byte, binary)
FIELDDC places right of decimal point if N field type, minimum if not 0 is
2, can be up to 6 or 8, non-N fields always 0 (1 byte, binary)
See: GetRecordXB
~GetRecordXB
Pack: AccessPack Src: GetRecordXBsrc Func: 31/Mid-level
Get the physical record from the data file into a data buffer by record number.
The data buffer is typically a TYPEd variable defined as the .DBF record itself
is defined. For example, if the DBF record has 2 fields, LNAME and FNAME, then
variable would be TYPEd as:
TYPE RecBuffer
tag AS STRING * 1 'the Xbase DBF delete flag (must be included)
LastName AS STRING * 25 'same field length as the .DBF LNAME field
FirstName AS STRING * 25 'same field length as the .DBF FNAME field
END TYPE
This method of accessing the data file does not use any indexing. Therefore, it
typically is not used except for special purposes. The preferred method to
access the data is by one of the keyed Get() routines.
See: AddRecordXB GetEqualXB
~AddRecordXB
Pack: AccessPack Src: AddRecordXBsrc Func: 32/Mid-level
Append the record in the data buffer to the end of the DBF file.
This method of adding a record does not involve any indexing. It is typically
used to build a data file en masse and do the indexing after the entire .DBF
file(s) has been built.
If you have several thousand data records to be added at once, this method of
building the DBF first and then using the ReindexXB routine is often faster
than using the InsertXB routine for each record to add.
The AddRecordXB is very fast. 400 recs/sec on an AT machine is typical. Over
2000 recs/sec can be added on a fast 486 machine--that's 120,000 records added
per minute.
The record number used is determined by BULLET and it is returned in AP.RecNo.
See: UpdateRecordXB InsertXB ReindexXB
~UpdateRecordXB
Pack: AccessPack Src: UpdateRecordXBsrc Func: 33/Mid-level
Write the updated data record to the the physical record number.
This method of writing the updated record must not be used if any field(s) in
the record is used as a key field(s) and has been changed.
This method of updating a record is very fast if you know that that update is
not going to alter any field used as a key in any index file that uses it. You
must, of course, first get the data record into the record buffer. Then you can
change it and write the update out to disk with this routine.
If you need to change a field(s) that is used as a key field or part of one,
use the UpdateXB routine. UpdateXB not only dynamically updates all related
index files if you change a key field, it also will undo any and all changes if
an error occurs in the transaction.
See: DeleteRecordXB GetRecordXB UpdateXB
~DeleteRecordXB
Pack: AccessPack Src: DeleteRecordXBsrc Func: 34/Mid-level
Tag the record at the physical record number as being deleted.
This does not tag any in-memory copies of the record so be sure to mark any
such copies as being deleted yourself.
The first byte of every .DBF record is reserved for the delete tag. This tag
is a space (ASCII 32) if the record is normal, or a * (ASCII 42) if it's marked
as being deleted. This delete tag is a reserved field in the DBF record and as
such is not defined as a formal field with a descriptor, etc. Make sure that
you define your in-memory buffers to reserve the first byte for the delete tag.
The Xbase DBF standard doesn't physically remove records marked as deleted from
the data file. It doesn't mark them as available/reusable either. To physically
remove records marked as deleted use PackRecordsXB.
Records can be temporarily marked as deleted then recalled to normal status.
The Key/Get routines (GetFirstXB, etc.) return the record number needed for
this routine after each access in AP.RecNo.
See: UndeleteRecordXB PackRecordsXB
~UndeleteRecordXB
Pack: AccessPack Src: UndeleteRecordsrc Func: 35/Mid-level
Tag the record at the physical record number as being normal (not deleted).
This does not tag any in-memory copies of the record so be sure to mark any
such copies as being normal yourself.
The first byte of every .DBF record is reserved for the delete tag. This tag
is a space (ASCII 32) if the record is normal, or a * (ASCII 42) if it's marked
as being deleted. This delete tag is a reserved field in the DBF record and as
such is not defined as a formal field with a descriptor, etc. Make sure that
you define your in-memory buffers to reserve the first byte for the delete tag.
The Xbase DBF standard does not physically remove records marked as deleted
from the data file so you can "recall" then back to normal status as easily as
you marked them deleted.
See: PackRecordsXB DeleteRecordXB
~PackRecordsXB
Pack: AccessPack Src: PackRecordsXBsrc Func: 36/Mid-level
Rebuild the open DBF file by physically removing all records marked as deleted.
Packing occurs in place using the existing file. It's recommended that you
use BackupFileXB to copy the current DBF file before using this routine in
case of a failure during the pack process.
The newly packed file is truncated to reflect the current, actual size.
If there are index files for this .DBF file, they MUST all be reindexed after
the pack process by using ReindexXB.
This routine dynamically allocates at least as many bytes as the length of
the record. More if available.
See: FirstKeyXB DeleteRecordXB BackupFileXB ReindexXB
~FirstKeyXB
Pack: AccessPack Src: FirstKeyXBsrc Func: 40/Mid-level
Retrieve the first key in index order from the index file.
This routine does not access the .DBF file and so does not retrieve the data
record. What it does do is locate the first key of the index, returning it,
and also returning the record number within the .DBF that the key indexes.
To retrieve the data record you can use the GetRecordXB routine. The preferred
method, however, is to use the GetFirstXB.
The key returned includes an enumerator if a non-unique index file is involved.
The enumerator is a little-endian 16-bit value that serves to differentiate
up to 65535 "identical", non-unique keys. It is attached to all keys of non-
unique index files and occupies the last two bytes of the key, high/low order
This routine is typically used to position the index file to the first key so
as to allow forward in-order access to the keys by using NextKeyXB.
See: EqualKeyXB GetFirstXB GetRecordXB
~EqualKeyXB
Pack: AccessPack Src: EqualKeyXBsrc Func: 41/Mid-level
Search for the exact key in the index file.
This routine does not access the .DBF file and so does not retrieve the data
record. What it does do is search for the key in the index, and if found,
returns the record number within the .DBF that the key indexes. The key must
be an exact match, including enumerator word if a non-unqiue index file.
To retrieve the data record you can use the GetRecordXB routine. The preferred
method, however, is to use the GetEqualXB.
This routine will only find EXACT matches to the specified key (including the
enumerator if applicable). However, even if the exact key is not found in the
index file, the index file is positioned so that the next NextKeyXB retrieves
the key that would have followed the unmatched specified key. For example,
if the key to match was "KINGS" (a partial key in this case), EqualKeyXB would
return a key not found error. If you were to now do a NextKeyXB, the next key
would be returned, let's say it is "KINGSTON".
See: NextKeyXB GetEqualXB GetRecordXB
~NextKeyXB
Pack: AccessPack Src: NextKeyXBsrc Func: 42/Mid-level
Retrieve the next key in index order from the index file.
This routine does not access the .DBF file and so does not retrieve the data
record. What it does do is retreive the next key of the index, returning it,
and also returning the record number within the .DBF that the key indexes.
To retrieve the data record you can use the GetRecordXB routine. The preferred
method, however, is to use the GetNextXB.
The key returned includes an enumerator if a non-unique index file is involved.
This routine is typically called after the index file has first been positioned
to a known key using either FirstKeyXB or EqualKeyXB, or after a previous
NextKeyXB or even PrevKeyXB. What it basically does is get the key following
the current key, and then make that key the new current key.
See: PrevKeyXB GetNextXB GetRecordXB
~PrevKeyXB
Pack: AccessPack Src: PrevKeyXBsrc Func: 43/Mid-level
Retrieve the previous key in index order from the index file.
This routine does not access the .DBF file and so does not retrieve the data
record. What it does do is retreive the previous key of the index, returning
it and also returning the record number within the .DBF that the key indexes.
To retrieve the data record you can use the GetRecordXB routine. The preferred
method, however, is to use the GetPrevXB.
The key returned includes an enumerator if a non-unique index file is involved.
This routine is typically called after the index file has first been positioned
to a known key using either LastKeyXB or EqualKeyXB, or after a previous
PrevKeyXB or even NextKeyXB. What it basically does is to get the key previous
the current key, and then make that key the new current key.
See: LastKeyXB GetPrevXB GetRecordXB
~LastKeyXB
Pack: AccessPack Src: LastKeyXBsrc Func: 44/Mid-level
Retrieve the last key in index order from the index file.
This routine does not access the .DBF file and so does not retrieve the data
record. What it does do is locate the last key of the index, returning it,
and also returning the record number within the .DBF that the key indexes.
To retrieve the data record you can use the GetRecordXB routine. The preferred
method, however, is to use the GetLastXB.
This routine is typically used to position the index file to the last key so as
to allow reverse in-order access to the keys by using PrevKeyXB.
See: StoreKeyXB GetLastXB GetRecordXB
~StoreKeyXB
Pack: AccessPack Src: StoreKeyXBsrc Func: 45/Mid-level
Insert the key into the index file in proper key order.
This routine does not add the data record to the .DBF file. It only inserts
the key and record number into the index file. Use InsertXB, instead.
To do a complete data record and key insert, you could use AddRecordXB to add
the data record to the .DBF, BuildKeyXB to construct the key, then StoreKeyXB
to insert the key and record number information into the index file. If that
key already exists and the file allows duplicate keys, you need to attach the
proper enumerator word and retry StoreKeyXB.
This is much too much to do. Instead, just use InsertXB. All these details
including adding the data record and multi-key inserts are performed
automatically with just the single call.
See: DeleteKeyXB InsertXB
~DeleteKeyXB
Pack: AccessPack Src: DeleteKeyXBsrc Func: 46/Mid-level
Physically remove the specified key from the index file.
This routine requires an EXACT key match for all bytes of the key, including
the enumerator word if a non-unique index file is involved.
This routine would seldom be used, typically, since deleted dBASE data records
are only physically deleted during a PackRecordsXB and the index file is
rebuilt afterward using ReindexXB.
See: BuildKeyXB CurrentKeyXB
~BuildKeyXB
Pack: AccessPack Src: BuildKeyXBsrc Func: 47/Mid-level
Build the key for the specifed data record based on the key expression for the
index file. If the index file is non-unique, a 0-value enumerator is attached.
The enumerator is a little-endian 16-bit value that serves to differentiate
up to 65535 "identical", non-unique keys. It is attached to all keys of non-
unique index files and occupies the last two bytes of the key.
This routine, like most of the mid-level routines, typically would not be used
since the high-level access routines take care of this detail automatically.
See: CurrentKeyXB StoreKeyXB
~CurrentKeyXB
Pack: AccessPack Src: CurrentKeyXBsrc Func: 48/Mid-level
Retrieve the current key value for the specified key file handle and also the
data record number that it indexes.
This routine is useful in that it retrieves on demand the actual key value of
the last accessed key in the index file (and the data record number). Most
often you don't need this information so it would be a waste of time and space
for your program to explicitly track each current key for each index file that
you have open.
See: GetFirstXB ReindexXB DeleteKeyXB
~GetFirstXB
Pack: AccessPack Src: GetFirstXBsrc Func: 60/High-level
Retrieve the first indexed key and data record.
The key returned includes an enumerator if a non-unique index file is involved.
This routine is typically used to process a database in index order starting at
the first ordered key (and its data record). After processing this first entry,
subsequent in-order access of the database is achieved by using GetNextXB until
the end of the database is reached.
This routine, like all the high-level Get routines, fills in the AP.RecNo of
the record accessed. In GetFirstXB's case, it fills AP.RecNo with the record
number pointed to by the first key. Since this is so, the AP pack is primed for
an UpdateXB after each high-level Get. Other methods to get the record number
are to use CurrKeyXB or any of the Key routines (KeyFirstXB, etc.).
See: GetEqualXB FirstKeyXB UpdateXB
~GetEqualXB
Pack: AccessPack Src: GetEqualXBsrc Func: 61/High-level
Search for the exact key in the index file and return its data record.
This routine will only find EXACT matches to the specified key (including the
enumerator if applicable). However, even if the exact key is not found in the
index file, the index file is positioned so that the next GetNextXB retrieves
the key that would have followed the unmatched specified key. For example,
if the key to match was "KINGS" (a partial key in this case), GetEqualXB would
return a key not found error. If you were to now do a GetNextXB, the next key
and data record would be returned, let's say the key is "KINGSTON" and its data
record is the data record for that key. Another GetNextXB would retrieve the
key and record after that. (GetPrevXB can be used in this fashion too.)
This routine, like all the high-level Get routines, fills in the AP.RecNo of
the record accessed. In GetEqualXB's case, it fills AP.RecNo with the record
number pointed to by the matched key. Since this is so, the AP pack is primed
for an UpdateXB after each high-level Get. Other methods to get the record
number are to use CurrKeyXB or any of the Key routines (KeyEqualXB, etc.).
See: GetNextXB EqualKeyXB
~GetNextXB
Pack: AccessPack Src: GetNextXBsrc Func: 62/High-level
Retrieve the next indexed key and its data record.
The key returned includes an enumerator if a non-unique index file is involved.
This routine is typically calld after the index file has first been positioned
to a known key using either GetFirstXB or GetEqualXB, or after a previous
GetNextXB or even GetPrevXB. What it basically does is get the key and data
record following the current key, and then make that key the new current key.
This routine, like all the high-level Get routines, fills in the AP.RecNo of
the record accessed. In GetNextXB's case, it fills AP.RecNo with the record
number pointed to by the next key. Since this is so, the AP pack is primed for
an UpdateXB after each high-level Get. Other methods to get the record number
are to use CurrKeyXB or any of the Key routines (KeyNextXB, etc.).
See: GetPrevXB NextKeyXB
~GetPrevXB
Pack: AccessPack Src: GetPrevXBsrc Func: 63/High-level
Retrieve the previous indexed key and record.
The key returned includes an enumerator if a non-unique index file is involved.
This routine is typically called after the index file has first been positioned
to a known key using either GetLastXB or GetEqualXB, or after a previous
GetPrevXB or even GetNextXB. What it basically does is to get the key and data
record previous the current key, and then make that key the new current key.
This routine, like all the high-level Get routines, fills in the AP.RecNo of
the record accessed. In GetPrevXB's case, it fills AP.RecNo with the record
number pointed to by the previous key. Since this is so, the AP pack is primed
for an UpdateXB after each high-level Get. Other methods to get the record
number are to use CurrKeyXB or any of the Key routines (KeyPrevXB, etc.).
See: GetLastXB PrevKeyXB
~GetLastXB
Pack: AccessPack Src: GetLastXBsrc Func: 64/High-level
Retrieve the last indexed key and record.
This routine is typically used to process a database in reverse index order
starting at the last ordered key (and its data record). After processing this
last entry, subsequent reverse-order access of the database is achieved by
using GetPrevXB until the top of the database is reached.
This routine, like all the high-level Get routines, fills in the AP.RecNo of
the record accessed. In GetLastXB's case, it fills AP.RecNo with the record
number pointed to by the last key. Since this is so, the AP pack is primed for
an UpdateXB after each high-level Get. Other methods to get the record number
are to use CurrKeyXB or any of the Key routines (KeyLastXB, etc.).
See: InsertXB LastKeyXB
~InsertXB
Pack: AccessPack Src: InsertXBsrc Func: 65/High-level
Add the data record to data file and insert the related key(s) into the linked
index file(s).
This routine is used to add new entries into a database, one at a time. The
data record is first added to the data file, then for each related index file,
a key is inserted into the appropriate index file. Up to 32 index files can be
automatically maintained for each data file.
This and several other routines are transaction-based. If a failure occurs
prior to the routine's completion, all changes made to the database by the
routine will be backed-out and the database (data and related index file(s))
effectively restored to its original state.
If the routine failed to complete, the function return value is the number of
the pack that caused the failure. The pack's Stat is checked to determine the
error code. If the function return value is 0, YOU MUST STILL check the first
pack's Stat. If it's non-zero, then the failure occured with the data record.
See: UpdateXB StoreKeyXB
~UpdateXB
Pack: AccessPack Src: UpdateXBsrc Func: 66/High-level
Modify an existing data record (identified by record number) and automatically
perform any index file updates needed to keep the index file(s) in sync.
If any key fields changed between the original record and the new one, this
routine updates the appropriate index file(s) by replacing the original key(s)
with new the key(s) based on the updated data record. Up to 32 index files can
be automatically maintained for each data file. Get routines (GetFirstXB, etc.)
set the AP.RecNo of the record that UpdateXB uses.
This and several other routines are transaction-based. If a failure occurs
prior to the routine's completion, all changes made to the database by the
routine will be backed-out and the database (data and related index file(s))
effectively restored to its original state.
If the routine failed to complete, the function return value is the number of
the pack that caused the failure. The pack's Stat is checked to determine the
error code. If the function return value is 0, YOU MUST STILL check the first
pack's Stat. If it's non-zero, then the failure occured with the data record.
See: ReindexXB UpdateRecordXB
~ReindexXB
Pack: AccessPack Src: ReindexXBsrc Func: 67/High-level
Reindex all related index files for a data file.
The index file(s) must already exist and be open. Any existing key data is
overwritten by the new key data. In other words, if you have a 10MByte index
file, ReindexXB uses the same file space building the news keys over the old.
This results in a less fragmented disk and also minimizes disk space needed.
You can also create a new, empty index file and reindex to that. This would be
useful, for instance, if you needed to create a temporary index file--something
that you'd use for a report, say, then delete after the report.
This routine creates a TEMPORARY work file in either the current directory or,
if the DOS environment variable TMP is defined, in the TMP= directory. The size
of this file is approx. bytes = (RECORDS * (KEYLEN+6)). ReindexXB can operate
in as little as 32K of available memory and can use up to 128K. The resultant
index file(s) are optimized for minimum size AND maximum retrieval speed.
If the routine failed to complete, the function return value is the number of
the pack that caused the failure. The pack's Stat is checked to determine the
error code. A return value of zero indicates no error occured.
See: LockXB PackRecordsXB
~LockXB
Pack: AccessPack Src: LockXBsrc Func: 80/Network
Lock all bytes in the index file handle(s) for exclusive use by the current
process and reload the index file header(s) from disk. Also lock all bytes in
the related data file and reload the data file header from disk.
The files must have been opened with the appropriate share attribute and not
in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
This routine is transaction-based and will lock all index files specified in
AccessPack and the data file. If any lock fails, all previous locks by this
routine are released. The return value indicates which access pack failed, if
any. This value is used as the index into the AccessPack group for you to
identify the error code. See LockXBsrc for determining this exactly.
Use the DriveRemoteXB and/or FileRemoteXB to determine if locking is necessary.
If the files are on a remote drive then it is best to use locking. Locking may
also be necessary on multitasking local machines accessing shared files.
This routine is a combination of LockKeyXB and LockDataXB.
See: UnlockXB LockKeyXB LockDataXB DriveRemoteXB FileRemoteXB
~UnlockXB
Pack: AccessPack Src: UnlockXBsrc Func: 81/Network
Unlock all bytes in the specified file handle(s) (previously locked) and flush
the file header(s) to disk (flush done before lock(s) released). Also unlock
all bytes in the related data file and flush the data file header to disk.
The files must have been opened with the appropriate share attribute and not
in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
This routine is transaction-based and will unlock all index files specified in
AccessPack and the data file. If an unlock fails the routine exits with a
return value indicating which access pack failed. This value is used as the
index into the AccessPack group for you to identify the error code. Note that
this routine does not attempt to re-lock those files unlocked successfully if
an error occurs in the transaction. If an error does occur (unlikely) you will
need to provide for unlocking the remaining files manually with the UnlockKeyXB
and UnlockDataXB routines. You should not rely on the operating system to
automatically unlock files when they're closed.
This routine is a combination of UnlockKeyXB and UnlockDataXB.
See: LockKeyXB UnlockKeyXB UnlockDataXB
~LockKeyXB
Pack: AccessPack Src: LockKeyXBsrc Func: 82/Network
Lock all bytes in the index file handle(s) for exclusive use by the current
process and reload the index file header(s) from disk.
The files must have been opened with the appropriate share attribute and not
in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
This routine is transaction-based and will lock all index files specified in
AccessPack. If any lock fails, all previous locks by this routine are released.
The return value indicates which access pack failed, if any. This value is used
as the index into the AccessPack group for you to identify the error code.
The advantage of using region locks (LockKeyXB locks the entire file region) to
control file access is that the file does not need to be opened/closed using
the Deny Read/Write sharing attribute. Opening the file for Deny None, and
controlling subsequent access with region locks, allows for faster processing
since files do not need to be constantly opened and closed, as they would if
access were controlled by opening with Deny Read/Write.
See: UnlockKeyXB LockXB
~UnlockKeyXB
Pack: AccessPack Src: UnlockKeyXBsrc Func: 83/Network
Unlock all bytes in the specified file handle(s) (previously locked) and flush
the file header(s) to disk (flush done before lock(s) released).
The files must have been opened with the appropriate share attribute and not
in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
This routine is transaction-based and will unlock all index files specified in
AccessPack. If an unlock fails the routine exits with a return value indicating
which access pack failed. This value is used as the index into the AccessPack
group for you to identify the error code.
All file locks should be released when exclusive access in no longer needed.
It is not recommended that you end your program without having released active
file locks. This is especially a valid concern for DOS versions prior to 5.0.
DOS 5 releases locks on files that are closed.
See: LockDataXB UnlockXB
~LockDataXB
Pack: AccessPack Src: LockDataXBsrc Func: 84/Network
Lock all bytes in the file handle's data file for exclusive use by the current
process and reload the data file header from disk. You must set AP.RecNo=0 to
do this. To lock a single record, set AP.RecNo=record# to lock.
The files must have been opened with the appropriate share attribute and not
in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
This routine locks the specified data file. If the handle specified is that of
an index file, that index file's related data file handle is used. For single-
record locks, AP.Handle must have a data file handle specified. Header loading
is not performed if locking a single record.
The advantage of using region locks (LockDataXB locks the entire file region)
to control file access is that the file does not need to be opened/closed using
the Deny Read/Write sharing attribute. Opening the file for Deny None, and
controlling subsequent access with region locks, allows for faster processing
since files do not need to be constantly opened and closed, as they would if
access were controlled by opening with Deny Read/Write.
See: UnlockDataXB
~UnlockDataXB
Pack: AccessPack Src: UnlockDataXBsrc Func: 85/Network
Unlock all bytes in the specified file handle (previously locked) and flush the
data file header to disk (flush done before lock released). To do this you must
set AP.RecNo=0. To unlock a single record, set AP.RecNo=record# to unlock.
The files must have been opened with the appropriate share attribute and not
in compatibility mode. SHARE.EXE MUST be installed or DOS error 1 is issued.
This routine unlocks the specified data file. If the handle specified is that
of an index file that index file's related datafile handle is used. For single-
record unlocks, AP.Handle must have a data file handle specified. Flushing is
not performed if unlocking a single record.
All file locks should be released when exclusive access in no longer needed.
It is not recommended that you end your program without having released active
file locks. This is especially a valid concern for DOS versions prior to 5.0.
DOS 5 releases locks on files that are closed.
See: DriveRemoteXB
~DriveRemoteXB
Pack: RemotePack Src: DriveRemoteXBsrc Func: 86/Network
Determine if specified drive is remote (default drive=0, A:=1, B=2, C=3...).
This routine uses INT21/44/sub function 09.
In addition to returning the IsRemote state, this routine sends back the result
of the DX register and also the install state of SHARE.EXE.
The meaning of the bitflags in Flags are (where IsRemote=0):
Bit Meaning drive...
1 1=uses 32-bit sectoring
6 1=accepts Generic IOCTL (for INT21/44/0D,0E,0Fh)
7 1=accepts Query IOCTL Device (INT21/44/11h)
9 1=is local but shared by other computers in the network
11 1=accepts Does-Device-Use-Removable-Media (INT21/44/08)
13 1=requires media descriptor in FAT
14 1=accepts Receive/Send Control Data from Block Device (INT21/44/04,05)
15 1=is Substitution drive (set by the DOS SUBST command)
(all other bits=0)
See: FileRemoteXB LockXB
~FileRemoteXB
Pack: RemotePack Src: FileRemoteXBsrc Func: 87/Network
Determine if specified handle of file or device is remote.
This routine uses INT21/44/sub function 0Ah.
In addition to returning the IsRemote state, this routine sends back the result
of the DX register and also the install state of SHARE.EXE.
Flags bit 7=1 then handle is device, =0 then handle is file.
Bit Meaning DEVICE... Bit Meaning DEVICE...(cont)
0 1=is console input device 13 1=is named pipe
1 1=is console output device 15 1=is remote, 0=is local
2 1=is null device (all other bits=0)
3 1=is clock device Bit Meaning FILE...
4 1=is special device 0-5 xxxxxx=drive number (0=A...)
5 1=is in binary mode, 0=in ASCII 6 1=has not been written to
6 0=returns EOF if device is read 12 1=is NoInherit
11 1=is network spooler 14 1=date/time not set at close
12 1=is NoInherit 15 1=is remote, 0=is local
(all other bits=0)
See: SetRetriesXB DriveRemoteXB LockXB
~SetRetriesXB
Pack: SetRetriesPack Src: SetRetriesXBsrc Func: 88/Network
Set the number of times DOS retries disk operations after a failure due to
file-sharing operations (locked file regions from LockXB routines).
This routine uses INT21/44/sub function 0Bh.
By default DOS retries an operation 3 times (without pausing between attempts)
before returning an error to the application.
If you change the default values it's recommended that the default state be
restored before your application ends (Retries=3, Pause=1).
These values are pretty much determined by trial-and-error. You may find that
adding a delay between retries returns fewer access-denied errors.
See: DeleteFileDOS LockXB
~DeleteFileDOS
Pack: DOSFilePack Src: DeleteFileDOSsrc Func: 100/DOS
Delete the specified file.
This routine uses DOS INT21/41 (interrupt 21h function 41h).
See: RenameFileDOS
~RenameFileDOS
Pack: DOSFilePack Src: RenameFileDOSsrc Func: 101/DOS
Rename a file. May also be used to move the file to a new directory within the
partition.
This routine uses DOS INT21/56.
If the specified directory differs from the file's directory, the file's
directory entry is moved to the new directory.
For example, if the FilenamePtr filename is C:\LP100\PROJ93A.INF and the
NewFilenamePtr filename is C:\ARCH\PROJ93A.INA, the file is essentially
renamed and also moved to the \ARCH directory.
See: CreateFileDOS
~CreateFileDOS
Pack: DOSFilePack Src: CreateFileDOSsrc Func: 102/DOS
Create a new file.
This routine uses INT21/3C.
The specified filename/pathname must NOT already exist.
The file created is not left open. You must OpenFileDOS to use it.
The attribute used during the create can be:
ATTRIBUTE VALUE MEANING
Normal 0 normal access permitted to file
Read-Only 1 read-only access permitted to file
Hidden 2 file does not appear in directory listing
System 4 file is a system file
Volume 8 FILENAME used as volume label if no current label
Archive 20h file is marked for archiving
See: AccessFileDOS OpenFileDOS
~AccessFileDOS
Pack: DOSFilePack Src: AccessFileDOSsrc Func: 103/DOS
Determine if the specified file can be accessed with the specified
access/sharing mode.
This routine uses INT21/3D and INT21/3E.
Basically, a Does-File-Exist routine. It uses the specified access/sharing
attributes when trying to open the file. For example, if you specify
DFP.Attr = &H42 (R/W access + Deny None sharing) and use AccessFileDOS on a
Read-Only DOS file, the return value would be DOS error 5, Access Denied.
See: OpenFileDOS
~OpenFileDOS
Pack: DOSFilePack Src: OpenFileDOSsrc Func: 104/DOS
Open the specified file with the specified access/sharing mode.
This routine uses INT21/3D.
ACCESS VALUE MEANING
Read-only 0 open for read-only access
Write-only 1 open for write-only access
Read/Write 2 open for read/write access
SHARE
Compatibility 0 any process may share file (not recommended)
Deny Read/Write 10h no other process may share file
Deny Write 20h no other process may share file for write
Deny Read 30h no other process may share file for read
Deny None 40h any process may share file except in Compatibilty
INHERIT mode
NoInheritFlag 80h if set child processes do not inherit file handles
(child process cannot inherit handle > 20)
The file access mode is a combination of ACCESS + SHARE + INHERIT.
See: SeekFileDOS OpenPack
~SeekFileDOS
Pack: DOSFilePack Src: SeekFileDOSsrc Func: 105/DOS
Position the DOS file pointer of the specified file to the specified position.
This routine uses INT21/42.
The position is a 32-bit value and is relative to either the start of the file,
the current file pointer position, or the end of the file.
Method Meaning
0 start move from the start of file (offset is a 32-bit unsigned value)
1 start move at the current position (offset a signed value)
2 start move at the end of file (offset a signed value)
For example, to move to the 511th byte of a file (byte 0 being the first), set
the offset value to 511 and use Method 0. On return, the absolute offset value
of the new position is returned. This is useful with Method 2 since you can
specify an offset of 0 and have the file length returned.
Never position the file pointer to before the start of file.
See: ReadFileDOS
~ReadFileDOS
Pack: DOSFilePack Src: ReadFileDOSsrc Func: 106/DOS
Read from the file or device the specified number of bytes into a buffer.
This routine uses INT21/3F.
On block devices (such as disks) input starts at the current file position and
the file pointer is repositioned to the last byte read +1.
It is possible to read less than the bytes specified without an error being
generated. Compare the bytes to read with the returned bytes read value. If
less then end of file was reached during the read, if 0 then file was at EOF.
By using DOS's predefined handles you can read from the keyboard (STDIN) by
using the STDIN handle, 0. The input will terminate after all specified bytes
have been read or after a CR (ASCII 0Dh). If more bytes are entered than were
requested, the next read will retrieve those excess bytes. Therefore, it's
suggested that you specify 129 bytes to input (DOS will process 127+CR/LF bytes
maximum when reading the STDIN device). Post-process the entered data by
scanning for the CR/LF.
See: ExpandFileDOS
~ExpandFileDOS
Pack: DOSFilePack Src: ExpandFileDOSsrc Func: 107/DOS
Expands the specified file by the specified number of bytes.
This routine uses INT21/42 and INT21/40.
This routine is useful in pre-allocating disk space. By reserving disk space in
advance you can guarantee that enough disk space will be available for a future
operation (especially if more than 1 process is running). You'll also be able
ensure that the disk space that a file does use is as contiguous as possible.
Database systems are dynamic and their files typically allocate new space on
an as-needed basis. This dynamic allocation can cause parts of a file to be
located throughout the disk system, possibly affecting performance drastically.
By pre-allocating the disk space you can be assured of consistent throughput
performance since the file is contiguous.
See: WriteFileDOS
~WriteFileDOS
Pack: DOSFilePack Src: WriteFileDOSsrc Func: 108/DOS
Write to the file or device the specified number of bytes from a buffer.
This routine uses INT21/40.
If the number of bytes written is less than the specified bytes, this routine
returns a -2 error code (or 65554 unsigned).
On block devices (such as disk) output starts at the current file position, and
the file pointer is repositioned to the last byte written +1.
If the specified bytes to write is 0, the file is truncated at the current
file pointer position.
By using DOS's predefined handles you can write to the screen (STDOUT) by
using the STDOUT handle, 1.
See: CloseFileDOS
~CloseFileDOS
Pack: DOSFilePack Src: CloseFileDOSsrc Func: 109/DOS
Close the file flushing any internal buffers, releasing any locked regions, and
update the directory entry to the correct size, date, and time.
This routine uses INT21/3E.
If you have opened a file using the DOS open routine you should close it when
you no longer need it.
This routine can be used to close the predefined DOS handles (0-4) and make
those handles available for reuse. Typically handles 0 and 1 should not be
closed by an application since they are the STDIN and STDOUT that DOS uses
for the current application (keyboard and screen).
Since BULLET provides for up to 250 user file handles for your applications it
isn't necessary for you to eek 3 more file handles by closing handles 2-4.
See: MakeDirDOS
~MakeDirDOS
Pack: DOSFilePack Src: MakeDirDOSsrc Func: 110/DOS
Create a new subdirectory.
This routine uses INT21/39.
See: DeleteFileDOS
~AccessPack
Src: InsertXBsrc Func: InsertXB and many more
TYPE AccessPack 'AP (AP is recommended pack name for DIM, AP.Func=)
Func AS INTEGER 'varies
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'OS handle
RecNo AS LONG ' in:rec number to get/delete/update (if applicable)
' in:set to single rec# to lock or set to 0 to lock all
'ret:record number of data record accessed
RecPtrOff AS INTEGER 'far pointer to record storage buffer
RecPtrSeg AS INTEGER
KeyPtrOff AS INTEGER 'far pointer to search key buffer
KeyPtrSeg AS INTEGER
NextPtrOff AS INTEGER 'far pointer to next key access pack
NextPtrSeg AS INTEGER 'or 0:0 if end of link or if N/A
END TYPE '22
The NextPtr variables are only used by InsertXB, UpdateXB, ReindexXB, and the
LockXB routines. NextPtr is used as a link to the next related access pack,
if any. Not all entries are used by all routines. Generally, any routine that
gets/puts user data to the database uses this pack.
See: BreakPack
~BreakPack
Src: BreakXBsrc Func: BreakXB
TYPE BreakPack 'BP
Func AS INTEGER '4
Stat AS INTEGER 'ret:completion status
Mode AS INTEGER '=0 disable Ctrl-C/Ctrl-Break, 1=restore
END TYPE '6 bytes
A simple pack.
See: CopyPack
~CopyPack
Src: BackupFileXBsrc Func: BackupFileXB, CopyDHXB, CopyKHXB
TYPE CopyPack 'CP
Func AS INTEGER '5=BackupFileXB,16=CopyDHXB,26=CopyKHXB
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'handle of BULLET file
FilenamePtrOff AS INTEGER 'far pointer to filenameZ
FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0)))
END TYPE '10
See: CreateDataPack
~CreateDataPack
Src: CreateDXBsrc Func: CreateDXB
TYPE CreateDataPackTYPE 'CDP
Func AS INTEGER '10
Stat AS INTEGER 'ret:completion status
FilenamePtrOff AS INTEGER 'far pointer to filenameZ to create
FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
NoFields AS INTEGER 'number of fields per record
FieldListPtrOff AS INTEGER 'far pointer to field list
FieldListPtrSeg AS INTEGER '(field list is of type FieldDescTYPE )
FileID AS INTEGER 'file signature byte, usually=3
END TYPE '16
The filename pointed at by the FilenamePtr variables should be a fixed-length
string (e.g., FILEN AS STRING * 80) so that VARSEG/VARPTR can be used to get
its memory address. The filename must end with a CHR$(0) immediately following
the last character of the filename: FILEN = YourFilename$ + CHR$(0).
The FieldListPtr variables point to an array of type FieldDescTYPE. This array
is dimensioned for as many fields as there are in the record and contains the
field descriptors, one for each field.
See: CreateKeyPack FieldDescTYPE
~CreateKeyPack
Src: CreateKXBsrc Func: CreateKXB
TYPE CreateKeyPack 'CKP
Func AS INTEGER '20
Stat AS INTEGER 'ret:completion status
FilenamePtrOff AS INTEGER 'far pointer to filenameZ
FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
KeyExpPtrOff AS INTEGER 'far pointer to key expressionZ
KeyExpPtrSeg AS INTEGER '(key expression must end with a CHR$(0))
XBlink AS INTEGER 'BULLET XB data file handle this key file indexes
KeyFlags AS INTEGER 'bit 0=unique,1=char,4=int,5=long,(E=NLS),F=signed
CodePageID AS INTEGER 'code page ID for NLS, -1 to use system default
CountryCode AS INTEGER 'country code number for NLS, -1 to use default
CollatePtrOff AS INTEGER 'far pointer to programmer-supplied collate table
CollatePtrSeg AS INTEGER 'or 0:0 if using system-determined NLS table
END TYPE '24
Bit 14 in KeyFlags (0Eh) is set by BULLET during CreateKXB if a collate table
is present.
See: DescriptorPack is_NLS
~DescriptorPack
Src: GetDescriptorXBsrc Func: GetDescriptorXB
TYPE DescriptorPack 'DP
Func AS INTEGER '30
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'BULLET data file handle to get information on
FieldNumber AS INTEGER 'field number to get info on, or if 0 then...
FD AS FieldDescTYPE '...search for DP.FD.FieldName
END TYPE '40
GetDescriptorXB allows you to get the field descriptor info for a particular
field number (as in the first field, or the 10th field, etc.) or, if you don't
know the physical field number, the routine can also get the info for a field
by field name.
To get the info for field number, say 5, set DP.FieldNumber = 5. The DP.FD
structure element is filled in with field 5's information.
To get the info for a field by fieldname, say LASTNAME, set DP.FieldNumber=0 &
DP.FD.FieldName = "LASTNAME" + STRING$(11,0)--the fieldname must be zero-filled
and zero-terminated--adding 11 ASCII zeroes ensures this requirement.
See: DOSFilePack FieldDescTYPE
~DOSFilePack
Src: AccessFileDOSsrc Func: AccessFileDOS
(all routines ending with DOS)
TYPE DOSFilePack 'DFP
Func AS INTEGER 'varies, see DeleteFileDOS for first of DOS routines
Stat AS INTEGER 'ret:completion status
FilenamePtrOff AS INTEGER 'far pointer to filenameZ
FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
Handle AS INTEGER 'in: handle to access ret: handle opened
ASmode AS INTEGER 'open access/sharing mode
Bytes AS INTEGER 'in: bytes to read ret: bytes read
SeekOffset AS LONG 'seek to file position
Method AS INTEGER 'seek method
BufferPtrOff AS INTEGER 'far pointer to read/write buffer
BufferPtrSeg AS INTEGER
Attr AS INTEGER 'file create directory entry attribute
NewNamePtrOff AS INTEGER 'far pointer to new filenameZ for rename
NewNamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
END TYPE '30
All of the xDOS routines use this pack. Often only a few of the structure
elements are used by any one of the routines. Set only those needed.
See: DVmonPack
~DVmonPack
Src: DVmonCXBsrc Func: DVmonCXB
TYPE DVmonPackTYPE 'THIS ROUTINE IS AVAILABLE ONLY IN THE DEBUG ENGINE
Func AS INTEGER '9
Stat AS INTEGER 'ret:completion status
Mode AS INTEGER '=0 disable montitoring, =1 enable
Handle AS INTEGER 'file handle to monitor
VideoSeg AS INTEGER 'segment to write screen image (e.g., &HB800)
END TYPE '10 bytes
This routine is supplied only in the BULLET debug engine. It displays real-time
monitoring information of a .DBF file or index and .DBF file pair including
searches, seeks, hits, current record number, current key, key node contents,
key node pointers, stack state, key and record counts, and other info.
By using the HereSeg value returned from StatKXB you can locate the searches,
seeks, and hits data at (DEF SEG=HereSeg: Seeks&=GetLongAt&(517): DEF SEG)
+513 Searches AS LONG ;keys searched for since open
+517 Seeks AS LONG ;nodes seeked since open
+521 Hits AS LONG ;seeks satisfied without disk access
See: ExitPack
~ExitPack
Src: InitXBsrc Func: ExitXB, AtExitXB
TYPE ExitPack 'EP
Func AS INTEGER '1=ExitXB, 2=AtExitXB
Stat AS INTEGER 'ret:completion status
END TYPE '4 bytes
See: FieldDescTYPE
~FieldDescTYPE
Src: CreateDXBsrc Func: CreateDXB
TYPE FieldDescTYPE 'this TYPE is used by CreateDataPack ONLY
FieldName AS STRING * 11 'zero-filled field name (use only ASCII 65-90,95)
FieldType AS STRING * 1 'C-har,N-umeric,D-ate,L-ogical,M-emo
FieldDA AS LONG '=0,reserved
FieldLength AS STRING * 1 'C=1-254,N=1-19(varies),D=8,L=1,M=10
FieldDC AS STRING * 1 'decimal places for FieldType=N (0,2-15)
A1 AS INTEGER '=0,reserved
A2 AS INTEGER '=0,reserved
filler AS STRING * 10 '=0,reserved
END TYPE '32
If you can can forgo dBASE compatility you can use the B field type. This type
is for fields that contain binary data (all dBASE fields contain ASCII text or
numeric strings). If you specify a FieldType = "B" for, say an integer field,
use a FieldLen = 2. If the field is a long integer, use FieldLen = 4. You can
also use this non-standard field type for indexing. See CreateKXB for more.
See: HandlePack CreateDataPack CreateKXB
~HandlePack
Src: CloseDXBsrc Func: CloseDXB, ReadDHXB, FlushDHXB, ZapDHXB
CloseKXB, ReadKHXB, FlushKHXB, ZapKHXB
'HP
TYPE HandlePack '12=CloseDXB,14=ReadDHXB,15=FlushDHXB,17=ZapDHXB
Func AS INTEGER '22=CloseKXB,24=ReadKHXB,25=FlushKHXB,27=ZapKHXB
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'handle of BULLET file
END TYPE '6
See: InitPack
~InitPack
Src: InitXBsrc Func: InitXB
TYPE InitPack 'IP
Func AS INTEGER '0
Stat AS INTEGER 'ret:completion status
JFTmode AS INTEGER 'expand JFT if non-zero
DOSver AS INTEGER 'ret:DOS version
Version AS INTEGER 'ret:BULLET version * 100
ExitOff AS INTEGER 'ret:far pointer to ExitXB routine, offset
ExitSeg AS INTEGER 'ret:segment of ExitXB
END TYPE '12 bytes
See: MemoryPack
~MemoryPack
Src: MemoryXBsrc Func: MemoryXB
TYPE MemoryPack 'MP
Func AS INTEGER '3
Stat AS INTEGER 'ret:completion status
Memory AS LONG 'ret:largest free OS memory block
END TYPE '8 bytes
See: OpenPack
~OpenPack
Src: OpenDXBsrc Func: OpenDXB, OpenKXB
TYPE OpenPack 'OP
Func AS INTEGER '11=OpenDXB,21=OpenKXB
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'ret:OS handle of file opened
FilenamePtrOff AS INTEGER 'far pointer to filenameZ to open
FilenamePtrSeg AS INTEGER '(filename must end with a CHR$(0))
ASmode AS INTEGER 'DOS access-sharing mode (see OpenFileDOS)
xbHandle AS INTEGER 'if opening key file this is its related data file
END TYPE '14 '(if opening data file xbHandle is not used)
'Note: you must supply xbHandle on index file opens
See: RemotePack OpenFileDOS
~RemotePack
Src: DriveRemoteXBsrc Func: DriveRemoteXB, FileRemoteXB
TYPE RemotePack 'RP
Func AS INTEGER '86=DriveRemoteXB,87=FileRemoteXB
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'handle/drive depending on routine
IsRemote AS INTEGER 'ret:0=local,1=remote
Flags AS INTEGER 'ret:dx register as returned by DOS
IsShare AS INTEGER 'ret:0=SHARE.EXE not loaded
END TYPE '12
See: SetRetriesPack
~SetRetriesPack
Src: SetRetriesXBsrc Func: SetRetriesXB
TYPE SetRetriesPack 'SRP
Func AS INTEGER '88
Stat AS INTEGER 'ret:completion status
Mode AS INTEGER '0=set DOS default else use Pauses/Retries below
Pause AS INTEGER '0-65535 loop counter between retries
Retries As INTEGER '0-65535 retries to access locked file
END TYPE '10
The default values for Retries is 3 and Pause is 1.
The Pause value is used as a simple loop counter used to waste time. This loop
IS dependent on CPU power so values are not portable across different machines.
Do not use unrealistic values. For example, don't set Retries to 30,000 unless
you really want to wait for DOS to try 30,000 times before returning an error!
See: StatDataPack
~StatDataPack
Src: StatDXBsrc Func: StatDXB
TYPE StatDataPackTYPE 'SDP
Func AS INTEGER '13
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'BULLET data file to get status on
FileType AS STRING * 1 'ret:1=BULLET XB data file
Dirty AS STRING * 1 'ret:0=not changed
Recs AS LONG 'ret:records in file
RecLen AS INTEGER 'ret:record length
Fields AS INTEGER 'ret:fields per record ()
f1 AS STRING * 1 'reserved (1=update DVmon)
LUyear AS STRING * 1 'ret:binary, year file last updated
LUmonth AS STRING * 1 'ret:month --LUs are 0 if DBF newly created
LUday AS STRING * 1 'ret:day
HereSeg AS INTEGER 'ret:this file's control segment
filler AS STRING * 10 'reserved
END TYPE '32
See: StatKeyPack
~StatKeyPack
Src: StatKXBsrc Func: StatKXB
TYPE StatKeyPack 'SKP
Func AS INTEGER '23
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'BULLET key file to get status on
FileType AS STRING * 1 'ret:0=BULLET XB key file
Dirty AS STRING * 1 'ret:0=not changed
Keys AS LONG 'ret:keys in file
KeyLen AS INTEGER 'ret:key length
XBlink AS INTEGER 'ret:related BULLET XB data file handle
XBrecno AS LONG 'ret:record number attached to current key
HereSeg AS INTEGER 'ret:this file's control segment
CodePageID AS INTEGER 'ret:code page ID number of key file sort
CountryCode AS INTEGER 'ret:country code number of key file sort
CollateTableSize AS INTEGER 'ret: size of collate table, 0 or 256
KeyFlags AS INTEGER 'ret:bit 0=unique,1=char,4=int,5=long,E=NLS,F=signed
filler AS STRING * 2
END TYPE '32
See: StatHandlePack
~StatHandlePack
Src: StatHandleXBsrc Func: StatHandleXB
TYPE StatHandlePack 'SHP
Func AS INTEGER '6
Stat AS INTEGER 'ret:completion status
Handle AS INTEGER 'file handle to get information on
ID AS INTEGER 'ret:0=XB index,1=XB data file,-1=not BULLET handle
END TYPE '8 bytes
See: XErrorPack
~XErrorPack
Src: GetExtErrorXBsrc Func: GetExtErrorXB
TYPE XErrorPack 'XEP
Func AS INTEGER '7
Stat AS INTEGER 'ret:extended error
Class AS INTEGER 'ret:error class
Action AS INTEGER 'ret:suggested action
Location AS INTEGER 'ret:error location
END TYPE '10 bytes
See: AccessPack Errors_DOS
~Errors_BULLET (200-209)
200 key not found - The search key for Equal was not matched exactly.
Next/Prev routines can be used to continue search from point of mismatch.
201 key already exists - Attempted to add a key that already exists in the
index file created to allow only unique keys.
202 end of file - A Next routine is past the last key of the index file.
203 top of file - A Prev routine is before the first key of the index file.
204 key file empty - A key access was attempted with no keys in the index file.
205 key type unknown - Generally indicates a corrupt index header (keyflags
unknown at key insert).
reserved,206-207
208 no more nodes - The index file has reached full capacity (32MB). ReindexXB
can often shrink an index file by 30 to 50%.
209 key file corrupt - The index file is corrupt (write attempt to node 0).
See: Errors_BULLET_b
~Errors_BULLET_b (210-232)
210 key file corrupt - The index file is corrupt (internal overflow).
reserved,211-219
220 incorrect DOS version - BULLET requires DOS 3.3 or later.
221 invalid key length - The key is > 62 bytes (or 64 if unique specified).
222 file not open - The specified handle is not an open BULLET file.
reserved,223
224 invalid record number - The specified record number is < 0, past the last
record number in the .DBF, or is > 16,777,215.
reserved,225-227
228 invalid filetype - The specified handle is not the correct type for the
operation (i.e., specifying a data file handle for a key file operation).
reserved,229-232
See: Errors_BULLET_c
~Errors_BULLET_c (233-243)
233 init not active - InitXB must be called before all others except MemoryXB.
234 init already active - InitXB has already been called. Use ExitXB first to
call InitXB more than once per process. (Make sure the xxP.Func <> 0.)
235 too many indexes - BULLET can handle up to 32 index files per transaction
record with the InsertXB and UpdateXB routines. Contact the author if you
need to allow for more than 32 index files/transaction record.
reserved,236-239
240 invalid key expression - The CreateKXB key expression could not be
evaluated.
reserved,241
242 field not found - The fieldname was not found in the descriptor area.
243 invalid field count - Too many fields were specified or the specified field
number is past the last field.
See: Errors_BULLET_d
~Errors_BULLET_d (244-255)
reserved,244-249
250 invalid country info - The specifed country code or code page ID is not
valid or not installed (according to DOS).
251 invalid collate table size - The specified country code/code page ID uses
a collate-sequence table > 256 bytes (2-byte characters as with Kanji).
252 invalid keyflags - The specified keyflags are invalid.
reserved,253-254
255 evaluation mode shutdown - BULLET evaluation period has completed.
You can reinstall to continue evaluation, though you may want to consider
your motives for reinstalling since the original evaluation period has
expired. This error occurs only after the evaluation period has expired.
It is not recommended that you continue to use BULLET after the evaluation
period. It is possible for no 255 error to be generated for quite some
time since it occurs only under certain load conditions and then only when
certain routine sequences are performed. The specified evaluation period of
21 days should be adhered to.
See: Errors_BASIC
~Errors_BASIC
1 NEXT without FOR 24 device timeout
2 syntax error 25 device fault
3 RETURN without GOSUB 26 FOR without NEXT
4 out of DATA 27 out of paper
5 illegal function call 29 WHILE without WEND
6 overflow 30 WEND without WHILE
7 out of memory reserved,31-32
8 label not defined 33 duplicate label
9 subscript out of range reserved,34
10 duplicate definition 35 subprogram not defined
11 division by zero reserved,36
12 illegal in direct mode 37 argument-count mismatch
13 type mismatch 38 array not defined
14 out of string space reserved,39
reserved,15 40 variable required
16 string formula too complex reserved,41-49
17 cannot continue 50 FIELD overflow
18 function not defined 51 internal error
19 no RESUME 52 bad file name or number
20 RESUME without error 53 file not found
reserved,21-23 54 bad file mode
See: Errors_BASIC_b
~Errors_BASIC_b
55 file already open reserved,77-79
56 FIELD statement active 80 feature removed
57 device I/O error 81 invalid name
58 file already exists 82 table not found
59 bad record length 83 index not found
reserved,60 84 invalid column
61 disk full 85 no current record
62 input past end of file 86 duplicate value for unique index
63 bad record number 87 invalid operation on null index
64 bad file name 88 database needs repair
reserved,65-66 89 insufficient ISAM buffers
67 too many files
68 device unavailable
69 communication-buffer overflow
70 permission denied
71 disk not ready
72 disk-media error
73 feature unavailable
74 rename across disks
75 path/File access error
76 path not found
See: Errors_DOS
~Errors_DOS
-2 disk full or unexpected end of file
-1 bad filename
0 no error
1 function not supported 19 disk write protected
2 file not found 20 unknown unit
3 path not found 21 drive not ready
4 too many open files 22 unknown command
5 access denied (see Specs_Networks) 23 data error (CRC)
6 handle invalid 24 bad request structure length
7 MCBs destroyed 25 seek error
8 not enough memory 26 unknown medium type
9 memory block address invalid 27 sector not found
10 environment invalid 28 printer out of paper
11 format invalid 29 write fault
12 access code invalid 30 read fault
13 data invalid 31 general failure
reserved-0Eh 32 sharing violation
15 disk drive invalid 33 lock violation
16 cannot remove current directory 34 disk change invalid/wrong disk
17 not same device 35 FCB unavailable
18 no more files 36 sharing buffer overflow
See: Errors_DOS_b
~Errors_DOS_b
37 code page mismatched 58 incorrect response from network
38 handle EOF 59 unexpected network error
39 handle disk full 60 incompatible remote adapter
reserved-28h 61 print queue full
reserved-29h 62 no spool space
reserved-2Ah 63 not enough space to print file
reserved-2Bh 64 network name deleted
reserved-2Ch 65 network access denied
reserved-2Dh 66 network device type incorrect
reserved-2Eh 67 network name not found
reserved-2Fh 68 network name limit exceeded
reserved-30h 69 NETBIOS session limit exceeded
reserved-31h 70 sharing temporarily paused
50 network request not supported 71 network request not accepted
51 remote computer not listening 72 print/disk redirection paused
52 duplicate name on network reserved-49h
53 network pathname not found reserved-4Ah
54 network busy reserved-4Bh
55 network device no longer exists reserved-4Ch
56 NETBIOS command limit exceeded reserved-4Dh
57 network adapter hardware error reserved-4Eh
See: Errors_DOS_c
~Errors_DOS_c
reserved-4Fh
DOS Class Codes
80 file exists
81 duplicate FCB 1 out of resources 7 application error
82 cannot make 2 temporary situation 8 not found
83 fail on INT24 3 authorization 9 bad format
84 out of structures 4 internal error 10 locked
85 already assigned 5 hardware failure 11 media failure
86 invalid password 6 system failure 12 already exists
87 invalid parameter 13 unknown
88 network write fault
reserved-59h DOS Action Codes DOS Locus Codes
90 sys comp not loaded
1 retry immediately 1 unknown
2 delay and retry 2 block device
3 reenter input 3 network
4 abort ASAP 4 serial device
5 abort immediately 5 memory
6 ignore error
7 user intervention
See: Errors_BULLET
~InitXBsrc
Func: InitXB Pack: InitPack Func: 0/System
DIM IP AS InitPack
DIM EP AS ExitPack
IP.Func = %InitXB 'InitXB defined in PBULLET.BI
IP.JFTmode = 1 'expand JFT to 255 handles
stat = BULLET(IP)
IF stat = 0 THEN
DOSmajor = IP.DOSver\256
DOSminor = IP.DOSver MOD 256
BULLETver = IP.Version
SegExitXB = IP.ExitSeg
OffExitXB = IP.ExitOff
EP.Func = %AtExitXB 'register ExitXB with _atexit shutdown routine
stat = BULLET(EP)
ENDIF
IF stat THEN 'error
See: ExitXBsrc
~ExitXBsrc
Func: ExitXB Pack: ExitPack Func: 1/System
DIM EP AS ExitPack
EP.Func = %ExitXB 'ExitXB defined in PBULLET.BI
stat = BULLET(EP)
The return value from ExitXB is currently always 0.
See: AtExitXBsrc
~AtExitXBsrc
Func: AtExitXB Pack: ExitPack Func: 2/System
DIM IP AS InitPack
DIM EP AS ExitPack
IP.Func = %InitXB
IP.JFTmode = 1
stat = BULLET(IP)
IF stat = 0 THEN
DOSmajor = IP.DOSver\256
DOSminor = IP.DOSver MOD 256
SegExitXB = IP.ExitSeg
OffExitXB = IP.ExitOff
'register ExitXB with _atexit shutdown routine
EP.Func = %AtExitXB 'AtExitXB defined in PBULLET.BI
stat = BULLET(EP) 'the return value is that returned from the compiler
'_atexit routine, 0=okay, anything else is an error
ENDIF 'indicating, for example, the _atexit register is full
IF stat THEN 'error
See: MemoryXBsrc
~MemoryXBsrc
Func: MemoryXB Pack: MemoryPack Func: 3/System
DIM MP AS MemoryPack
WorkSpace& = 50000 'a value at least 40K or so
MemoryNeeded& = WorkSpace& + (144&+ ((1+NF)*32)) * TotalOpenDataFiles _
+ (1264& * TotalOpenKeyFiles)
MP.Func = %MemoryXB
stat = BULLET(MP)
IF MP.Memory < MemoryNeeded& THEN
QBheap& = SETMEM(-MemoryNeeded& + 4096) 'release what we need+QB fudge
MP.Func = %MemoryXB
stat = BULLET(MP)
IF MP.Memory < MemoryNeeded& THEN 'not enough memory
END IF
MP.Memory does not reflect memory available through DOS in the UMB area. It's
possible that all memory requests can be satisfied by UMB RAM. Consult a DOS 5+
programmer reference for more information on this (see DOS INT21/58 for more).
In the QuickBASIC/BASIC PDS environment do not call SETMEM(-x) more than once.
See: BreakXBsrc
~BreakXBsrc
Func: BreakXB Pack: BreakPack Func: 4/System
DIM BP AS BreakPack
BP.Func = %BreakXB 'BreakXB defined in PBULLET.BI
BP.Mode = 0 'disable Ctrl-C/Ctrl-BREAK (do nothing on those keys)
stat = BULLET(BP) 'stat=0 always
If BreakXB is called multiple times with the same BP.mode each time, only the
first is acted on. You can set BP.mode = 1 to restore the default handlers
(those installed originally) and then again set BP.Mode = 0 to disable them.
ExitXB calls this routine automatically as part of the BULLET shutdown to
restore the original default break handlers.
See: BackupFileXBsrc
~BackupFileXBsrc
Func: BackupFileXB Pack: CopyPack Func: 5/System
DIM AP AS AccessPack
DIM CP AS CopyPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
'so same source QB AND BASIC7 /Fs compatible
TempStr = NewFilename$ 'assign the var-len string to fixed-len str
CP.Func = %BackupFileXB 'defined in PBULLET.BI
CP.Handle = DataHandle 'handle of data file to backup
CP.FilenamePtrOff = VARPTR(TempStr) 'ALWAYS use VARPTR() on fixed-len string
CP.FilenamePtrSeg = VARSEG(TempStr) 'ALWAYS use VARSEG() on fixed-len string
stat = BULLET(CP) 'copy the data file to the file NewFilename$
IF stat = 0 THEN
AP.Func = %PackRecordsXB
AP.Handle = DataHandle
stat = BULLET(AP)
ENDIF
IF stat THEN 'error
See: StatHandleXBsrc
~StatHandleXBsrc
Func: StatHandleXB Pack: StatHandlePack Func: 6/System
DIM SHP AS StatHandlePack
DIM SKP AS StatKeyPack
DIM SDP AS StatDataPack
SHP.Func = %StatHandleXB 'defined in PBULLET.BI
SHP.Handle = TheHandleNumber
stat = BULLET(SHP)
IF SHP.ID = 0 THEN 'handle belongs to an index file (index file/key file)
SKP.Func = %StatKXB 'get key stats -- see StatKXB/StatDXB for more
SKP.Handle = PassedHandleNumber ' on the SKP structure
stat = BULLET(SKP)
ELSEIF SHP.ID = 1 THEN '.DBF data file
'get DBF stats
'error not a BULLET file type
ENDIF
See: GetExtErrorXBsrc
~GetExtErrorXBsrc
Func: GetExtErrorXB Pack: XErrorPack Func: 7/System
'an error just occured in the range 1 to 199 as returned in one of the
'pack.Stat variables (current max DOS error is 90 (5Ah))
'remember, transaction-based routines return a bad pack index in the return
'stat value, which you use to check the appropriate pack.Stat variable
DIM XEP AS XErrorPack
XEP.Func = %GetExtErrorXB 'defined in PBULLET.BI
stat = BULLET(XEP)
IF stat <> 0 THEN
PRINT "Extended Codes --"
PRINT " error: "; XEP.Stat
PRINT " error class: "; XEP.Class
PRINT "recommened action: "; XEP.Action
PRINT " location: "; XEP.Location
PRINT "No error"
ENDIF
See: DVmonCXBsrc StatKXB
~DVmonCXBsrc
Func: DVmonCXB Pack: DVmonPack Func: 9/DEBUG
'at this point a data file and a key file have been opened
'kf is that key file's DOS handle
DIM DV AS DVmonPack
DV.Func = %DVmonCXB 'defined in PBULLET.BI
DV.Mode = 1 'enable monitoring
DV.Handle = kf 'monitor key file handle, kf (and its XBlink data file)
DV.VideoSeg = &HB800+(4096\16) 'output to color screen, page 1 (pages 0 to ?)
stat = BULLET(DV) 'stat=0 always even if not DEBUG ENGINE
For two-monitor systems (with a color monitor as the main system) output should
be directed to &HB000, the mono monitor's video memory.
DVmonCXB stands for Dual Video Monitor Control XB.
See: CreateDXBsrc
~CreateDXBsrc
Func: CreateDXB Pack: CreateDataPack Func: 10/Mid-level
DIM CDP AS CreateDataPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
REDIM FD(1 TO 2) AS FieldDescTYPE 'field descriptions for each of the fields...
'...in the record (record has 2 fields)
TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
'...so we can use VARSEG/VARPTR
'build FD first for each of the fields in the record
FD(1).FieldName = "STUDENT" + STRING$(10,0) 'must be zero-filled
FD(1).FieldType = "C" 'a character field type
FD(1).FieldLength = CHR$(20) 'up to 20 characters (a byte field--use CHR$())
FD(1).FieldDC = CHR$(0) 'non-numeric has no decimal places
FD(2).FieldName = "SCORE" + STRING$(10,0)
FD(2).FieldType = "N"
FD(2).FieldLength = CHR$(3) 'dBASE numeric format, allow for "100"
FD(2).FieldDC = CHR(0) 'no decimal places used for this field
'(cont)
'for BINARY FieldType="B" see FieldDescTYPE
See: CreateDXBsrc_a -MORE-
~CreateDXBsrc_a
'build the CDP
CDP.Func = %CreateDXB 'defined in PBULLET.BI
CDP.FilenamePtrOff = VARPTR(TempStr) 'point to filenameZ (Z=0-terminated str)
CDP.FilenamePtrSeg = VARSEG(TempStr)
CDP.NoFields = 2 'this example has 2 fields
CDP.FieldListPtrOff = VARPTR(FD(1)) 'point to the first field decription...
CDP.FieldListPtrSeg = VARPTR(FD(1)) '...defined in the previous screen
CDP.FileID = 3 'standard dBASE file ID
stat = BULLET(CDP) 'create the DBF data file
IF stat THEN 'error
Normally this code would be written as a generalized FUNCTION. The CDP could be
a global allocation (DIM SHARED CDP AS CreateDataPack) and the FD() would also
be (REDIM [SHARED] FD(1 TO 1) AS FieldDescTYPE) and REDIM'd to needed size when
used. A possible header:
DECLARE FUNCTION CreateDBF% (filename$, NoFields%, FD() AS FieldDescTYPE)
To create a DBF you'd need just the filename, number of fields, REDIM the FD()
array (if needed), fill in FD() array, then call the function. Look at the
source code examples on the distribution disk for more.
See: OpenDXBsrc CreateDXBsrc
~OpenDXBsrc
Func: OpenDXB Pack: OpenPack Func: 11/Mid-level
DIM OP AS OpenPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
OP.Func = %OpenDXB 'defined in PBULLET.BI
OP.FilenamePtrOff = VARPTR(TempStr) 'point to filenameZ (Z=0-terminated str)
OP.FilenamePtrSeg = VARSEG(TempStr)
OP.ASmode = ReadWrite + DenyNone 'defined in PBULLET.BI
stat = BULLET(OP)
IF stat THEN 'error
The ASmode (access/sharing mode) determines how the operating system controls
access to the file. See OpenFileDOS for the meanings of the various ASmodes.
See: CloseDXBsrc OpenFileDOS
~CloseDXBsrc
Func: CloseDXB Pack: HandlePack Func: 12/Mid-level
DIM HP AS HandlePack
HP.Func = %CloseDXB 'defined in PBULLET.BI
HP.Handle = datahandle 'handle of the file to close
stat = BULLET(HP)
IF stat THEN 'error
See: StatDXBsrc
~StatDXBsrc
Func: StatDXB Pack: StatDataPack Func: 13/Mid-level
DIM SDP AS StatDataPack
SDP.Func = %StatDXB 'defined in PBULLET.BI
SDP.Handle = datahandle 'data handle to get stats on
stat = BULLET(SDP) 'must be a data handle, use StatHandleXB if you...
IF stat = 0 THEN '...don't know the type of file a handle's for
'SDP.FileType is set to 1
'SDP.Dirty is set to 1 if the file has changed (0=not changed)
'SDP.Recs = number of records in the DBF file
'SDP.RecLen = record length
'SDP.Fields = number of fields in the record
'SDP.f1 is reserved
'SDP.LUyear = year file last updated, binary (year = ASC(SDP.LUyear))
'SDP.LUmonth = month, binary
'SDP.LUday = day, binary
'SDP.HereSeg is set to this handle's control segment (location in memory)
'error
ENDIF
See: ReadDHXBsrc
~ReadDHXBsrc
Func: ReadDHXB Pack: HandlePack Func: 14/Mid-level
DIM HP AS HandlePack
HP.Func = %ReadDHXB 'defined in PBULLET.BI
HP.Handle = datahandle 'handle of file whose header you want to reload
stat = BULLET(HP)
IF stat THEN 'error
This routine is automatically called by the network lock routines.
See: FlushDHXBsrc LockDataXB
~FlushDHXBsrc
Func: FlushDHXB Pack: HandlePack Func: 15/Mid-level
DIM HP AS HandlePack
HP.Func = %FlushDHXB 'defined in PBULLET.BI
HP.Handle = datahandle 'handle of file you want to flush
stat = BULLET(HP)
IF stat THEN 'error
Note that the physical write to disk is performed only if the file has changed
since the open or last flush.
This routine is automatically called by the network unlock routines.
See: CopyDHXBsrc UnlockDataXB
~CopyDHXBsrc
Func: CopyDHXBsrc Pack: CopyPack Func: 16/Mid-level
DIM CP AS CopyPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
CP.Func = %CopyDHXB 'defined in PBULLET.BI
CP.Handle = datahandle 'handle of file to copy from (the source)
CP.FilenamePtrOff = VARPTR(TempStr) 'far pointer to filenameZ for copy
CP.FilenamePtrSeg = VARPTR(TempStr) '(the destination)
stat = BULLET(CP)
IF stat THEN 'error
See: ZapDHXBsrc
~ZapDHXBsrc
Func: ZapDHXB Pack: HandlePack Func: 17/Mid-level
DIM HP AS HandlePack
HP.Func = %ZapDHXB 'defined in PBULLET.BI
HP.Handle = datahandle 'handle of file you want !ZAP!
stat = BULLET(HP)
IF stat THEN 'error
Note that this removes ALL data records from the data file.
See: CreateKXBsrc
~CreateKXBsrc
Func: CreateKXB Pack: CreateKeyPack Func: 20/Mid-level
'This code assumes that the datafile was created as in CreateDXBsrc, and that
'the datafile was opened as in OpenDXBsrc.
kx$ = "SUBSTR(STUDENT,1,5)" 'key expression, a non-unique, character key
DIM CKP AS CreateKeyPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
DIM TempStr2 AS STRING * 136 'used as fixed-length string for VARPTR()
TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string
TempStr2 = kx$ + CHR$(0) 'same for key expression string
'(cont)
See: CreateKXBsrc_a -MORE-
~CreateKXBsrc_a
CKP.Func = %CreateKXB 'defined in PBULLET.BI
CKP.FilenamePtrOff = VARPTR(TempStr) 'far pointer to filenameZ
CKP.FilenamePtrSeg = VARSEG(TempStr)
CKP.KeyExpPtrOff = VARPTR(TempStr2) 'far pointer to key expressionZ
CKP.KeyExpPtrSeg = VARSEG(TempStr2)
CKP.XBlink = datahandle 'the datafile handle returned from OpenDXB
CKP.KeyFlags = cCHAR '-KEYFLAGS- are defined in PBULLET.BI
CKP.CodePageID = -1 'use DOS default code page ID
CKP.CountryCode = -1 'use DOS default country code
CKP.CollatePtrOff = 0 'no user-supplied collate table...
CKP.CollatePtrSeg = 0 '...
stat = BULLET(CKP)
IF stat THEN 'error
Normally this code would be written as a generalized FUNCTION. The CKP could be
a global allocation (DIM SHARED CKP AS CreateKeyPack). A possible header:
DECLARE FUNCTION CreateNewIndex% (filename$, datahandle, kx$, KeyFlags%)
To create an index file you'd need just filename, datahandle, key expression,
and key flags (country code info if not using default), then call the function.
See: OpenKXBsrc CreateKXBsrc
~OpenKXBsrc
Func: OpenKXB Pack: OpenPack Func: 21/Mid-level
DIM OP AS OpenPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
OP.Func = %OpenKXB 'defined in PBULLET.BI
OP.FilenamePtrOff = VARPTR(TempStr) 'point to filenameZ (Z=0-terminated str)
OP.FilenamePtrSeg = VARSEG(TempStr)
OP.ASmode = ReadWrite + DenyNone 'defined in PBULLET.BI
OP.XBlink = datafilehandle 'OpenKXB needs to know the data file handle
stat = BULLET(OP)
IF stat THEN 'error
The ASmode (access/sharing mode) determines how the operating system controls
access to the file. See OpenFileDOS for the meanings of the various ASmodes.
Before you can open an index file you must first open its associated data file.
See: CloseKXBsrc OpenFileDOS
~CloseKXBsrc
Func: CloseKXB Pack: HandlePack Func: 22/Mid-level
DIM HP AS HandlePack
HP.Func = %CloseDXB 'defined in PBULLET.BI
HP.Handle = indexhandle 'handle of the file to close
stat = BULLET(HP)
IF stat THEN 'error
See: StatKXBsrc
~StatKXBsrc
Func: StatKXB Pack: StatKeyPack Func: 23/Mid-level
DIM SKP AS StatKeyPack
SKP.Func = %StatKXB 'defined in PBULLET.BI
SKP.Handle = indexhandle 'handle to get stats on
stat = BULLET(SKP) 'must be index handle, use StatHandleXB if you...
IF stat = 0 THEN '...don't know the type of file a handle's for
'SKP.FileType is set to 0
'SKP.Dirty is set to 1 if the file has changed (0=not changed)
'SKP.Keys = number of key in the index file (index file=key file)
'SKP.KeyLen = physical key length (1-64 bytes)
'SKP.XBlink = datafile handle that this index file is associated with
'SKP.XBrecno is set to record number associated with last accessed key
'SKP.HereSeg is set to this handle's control segment (location in memory)
'SKP.CodePageID returns this index file's permanent code page ID
'SKP.CountryCode returns this index file's permanent country code
'SKP.CollateTableSize = 0 (no collate table present) or 256 (table present)
'SKP.KeyFlags = key flags specifed at CreateKXB (except NLS flag may be set)
ELSE (NLS flag is bit 14, &H4000)
'error
See: ReadKHXBsrc
~ReadKHXBsrc
Func: ReadKHXB Pack: HandlePack Func: 24/Mid-level
DIM HP AS HandlePack
HP.Func = %ReadKHXB 'defined in PBULLET.BI
HP.Handle = indexhandle 'handle of file whose header you want to reload
stat = BULLET(HP)
IF stat THEN 'error
This routine is automatically called by the network lock routines.
See: FlushKHXBsrc LockKeyXB
~FlushKHXBsrc
Func: FlushKHXB Pack: HandlePack Func: 25/Mid-level
DIM HP AS HandlePack
HP.Func = %FlushKHXB 'defined in PBULLET.BI
HP.Handle = indexhandle 'handle of file you want to flush
stat = BULLET(HP)
IF stat THEN 'error
Note that the physical write to disk is performed only if the file has changed
since the open or last flush.
This routine is automatically called by the network unlock routines.
See: CopyKHXBsrc UnlockKeyXB
~CopyKHXBsrc
Func: CopyKHXBsrc Pack: CopyPack Func: 26/Mid-level
DIM CP AS CopyPack
DIM TempStr AS STRING * 80 'used as fixed-length string for VARPTR()
TempStr = filename$ + CHR$(0) 'assign filename to a fixed-len string...
CP.Func = %CopyKHXB 'defined in PBULLET.BI
CP.Handle = indexhandle 'handle of file to copy from (the source)
CP.FilenamePtrOff = VARPTR(TempStr) 'far pointer to filenameZ for copy
CP.FilenamePtrSeg = VARPTR(TempStr) '(the destination)
stat = BULLET(CP)
IF stat THEN 'error
See: ZapKHXBsrc
~ZapKHXBsrc
Func: ZapKHXB Pack: HandlePack Func: 27/Mid-level
DIM HP AS HandlePack
HP.Func = %ZapKHXB 'defined in PBULLET.BI
HP.Handle = indexhandle 'handle of file you want !ZAP!
stat = BULLET(HP)
IF stat THEN 'error
Note that this removes ALL keys from the index file.
See: GetDescriptorXBsrc
~GetDescriptorXBsrc
Func: GetDescriptorXB Pack: DescriptorPack Func: 30/Mid-level
DIM DP AS DescriptorPack
DP.Func = %GetDescriptorXB 'defined in PBULLET.BI
DP.Handle = datahandle 'handle of file
IF FieldNumber > 0 THEN
DP.FieldNumber = FieldNumber 'field number to get info on
ELSE 'or, if 0, then
DP.FieldNumber = 0
DP.FD.FieldName = fieldname$ + STRING$(10,0) 'fieldname$ to get info on
ENDIF
stat = BULLET(DP)
IF stat = 0 THEN
'DP.FD.FieldName is set to field name
'DP.FD.FieldType is set to field type
'DP.FD.FieldLen is set to field length
'DP.FD.FieldDC is set to field DC
ELSE
'error
The DP.FD.FieldLen (and DP.FD.FieldDC) is a byte string so you
need to use a FldLen=ASC(DP.FD.FieldLen) for its integer value
See: GetRecordXBsrc
~GetRecordXBsrc
Func: GetRecordXB Pack: AccessPack Func: 31/Mid-level
TYPE RecordTYPE 'simple DBF record layout
tag AS STRING * 1 <
code AS STRING * 4
THE FIRST BYTE OF YOUR RECORD TYPES MUST BE TAG!
bday AS STRING * 8
END TYPE
DIM RecBuff AS RecordTYPE 'record has 2 fields, code/C/4.0, bday/D/8.0
DIM AP AS AccessPack
AP.Func = %GetRecordXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle to get record from
AP.RecNo = RecnoToGet& 'record number to get
AP.RecPtrOff = VARPTR(RecBuff) 'read record from disk into RecBuff
AP.RecPtrSeg = VARSEG(RecBuff)
stat = BULLET(AP)
IF stat = 0 THEN
PRINT RecBuff.code ; ", " ; RecBuff.bday 'sample output: 4321, 19331122
'error
See: AddRecordXBsrc
~AddRecordXBsrc
Func: AddRecordXB Pack: AccessPack Func: 32/Mid-level
TYPE RecordTYPE 'simple DBF record layout
tag AS STRING * 1 <
code AS STRING * 4
THE FIRST BYTE OF YOUR RECORD TYPES MUST BE TAG!
bday AS STRING * 8
END TYPE
DIM RecBuff AS RecordTYPE 'record has 2 fields, code/C/4.0, bday/D/8.0
DIM AP AS AccessPack
'be sure to init the tag field to a space (ASCII 32)
RecBuff.tag = " " : RecBuff.code = "1234" : RecBuff.bday = "19331122"
AP.Func = %AddRecordXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle to add record to
AP.RecPtrOff = VARPTR(RecBuff) 'write record from RecBuff to disk...
AP.RecPtrSeg = VARSEG(RecBuff) '...at next available record number
stat = BULLET(AP)
IF stat = 0 THEN
PRINT "Record number used by AddRecordXB was "; AP.RecNo
ELSE 'error
See: UpdateRecordXBsrc
~UpdateRecordXBsrc
Func: UpdateRecordXB Pack: AccessPack Func: 33/Mid-level
'see GetRecordXBsrc for this source example's preliminary code
AP.Func = %GetRecordXB 'first get the record to update
AP.Handle = datahandle
AP.RecNo = RecnoToGet& '
AP.RecPtrOff = VARPTR(RecBuff) '
Do NOT use UpdateRecordXB to change
AP.RecPtrSeg = VARSEG(RecBuff) '
any field(s) used in a key expression.
stat = BULLET(AP) '
Instead use UpdateXB.
IF stat = 0 THEN '
RecBuff.dbay = "19591122" 'change only non-key portions of record
AP.Func = %UpdateRecordXB 'defined in PBULLET.BI
stat = BULLET(AP) 'other AP. values are already set from the Get
IF stat THEN 'though you should reassign AP.RecPtrOff/Seg if
'error 'you perform any BASIC string functions between
'BULLET calls (none were in this case).
NOTE: QB/PDS will move strings
'--by this I mean to set these again
after a user-break/Ctrl-Break
' AP.RecPtrOff = VARPTR(RecBuff)
in the QB/QBX environment !!!
' AP.RecPtrSeg = VARSEG(RecBuff)
' stat = BULLET(AP) 'do the update call
See: DeleteRecordXBsrc UpdateXB
~DeleteRecordXBsrc
Func: DeleteRecordXB Pack: AccessPack Func: 34/Mid-level
DIM AP AS AccessPack
AP.Func = %DeleteRecordXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle of record to delete
AP.RecNo = RecnoToDelete& 'to determine which record number any record
stat = BULLET(AP) 'is, use one of the keyed access routines
IF stat THEN 'error
See: UndeleteRecordsrc (XB)
~UndeleteRecordsrc (XB)
Func: UndeleteRecordXB Pack: AccessPack Func: 35/Mid-level
DIM AP AS AccessPack
AP.Func = %UndeleteRecordXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle of record to undelete
AP.RecNo = RecnoToUndelete& 'to determine which record number any record
stat = BULLET(AP) 'is use one of the keyed access routines
IF stat THEN 'error
See: PackRecordsXBsrc
~PackRecordsXBsrc
Func: PackRecordsXB Pack: AccessPack Func: 36/Mid-level
DIM AP AS AccessPack
AP.Func = %PackRecordsXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle of data file to pack
stat = BULLET(AP)
IF stat THEN 'error
See: FirstKeyXBsrc
~FirstKeyXBsrc
Func: FirstKeyXB Pack: AccessPack Func: 40/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
'needs to be at least key length (MAXKEYLEN=64)
AP.Func = %FirstKeyXB 'defined in PBULLET.BI
AP.Handle = indexhandle 'handle to index file to access key from
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the first key is read from disk and put here)
stat = BULLET(AP)
IF stat = 0 THEN
'TempStr is filled in with the key (for as many bytes as the key length)
'so, if the key is a character type, you could PRINT LEFT$(TempStr,KeyLen)
'or, if key is a 32-bit LONG then PRINT CVL(LEFT$(TempStr,4)). When using
'the key returned, be aware that if UNIQUE was NOT specified then the
'enumerator word is attached to the end of the key (the right two bytes).
'Also, AP.RecNo is set to the record number of the first key in the index.
'error
See: EqualKeyXBsrc
~EqualKeyXBsrc
Func: EqualKeyXB Pack: AccessPack Func: 41/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
'passed key to find, start with enum=0
TempStr = FindKey$ + CHR$(0) + CHR$(0) + CHR$(0) '2 enumerator bytes + 0-term
AP.Func = %EqualKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file to find key from
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr)
stat = BULLET(AP)
IF stat = 0 THEN
'the key matched exactly (including enumerator, if present)
'TempStr is NOT ALTERED
'AP.RecNo is set to the record number of that key
ELSEIF stat = 200 THEN
AP.Func = %NextKeyXB 'if not found, get following key and check the
stat = BULLET(AP) 'key proper (key less the enumerator bytes)
IF stat = 0 THEN '(i.e., it may be proper key but enumerator=1)
'see NextKeyXBsrc for continuation
See: NextKeyXBsrc
~NextKeyXBsrc
Func: NextKeyXB Pack: AccessPack Func: 42/Mid-level
'see EqualKeyXBsrc for preliminary code
AP.Func = %NextKeyXB 'defined in PBULLET.BI
stat = BULLET(AP) 'KEYLEN assumed to equal actual key length...
IF stat = 0 THEN '...as returned by StatKXB
IF IndexFileIsNotUnique THEN
IF LEFT$(TempStr,KeyLen-2) = FindKey$ THEN 'the next key matches!
'(except for the enumerator)
This code example follows up on the EqualKeyXBsrc example. See EqualKeyXB for
more information on finding partial keys.
See: PrevKeyXBsrc EqualKeyXBsrc
~PrevKeyXBsrc
Func: PrevKeyXB Pack: AccessPack Func: 43/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
'assume code has already executed to locate a key--this code then gets the key
'before that one
AP.Func = %PrevKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file to access key from
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the prev key is read from disk and put here)
stat = BULLET(AP)
IF stat = 0 THEN
'TempStr is filled in with the key (for as many bytes as the key length).
'Also, AP.RecNo is set to the record number of the key.
'error
See: LastKeyXBsrc
~LastKeyXBsrc
Func: LastKeyXB Pack: AccessPack Func: 44/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
AP.Func = %LastKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file to access key from
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
stat = BULLET(AP)
IF stat = 0 THEN
'TempStr is filled in with the key (for as many bytes as the key length)
'AP.RecNo is set to the record number of the last key.
'error
See: StoreKeyXBsrc
~StoreKeyXBsrc
Func: StoreKeyXB Pack: AccessPack Func: 45/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
'Assume record has been added to data file (AddRecordXB, returning RecNo2Use)
'and key has been built (BuildKeyXB returning KeyToAdd$).
TempStr = KeyToAdd$ + CHR$(0) 'add the key to a UNIQUE index file
AP.Func = %StoreKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file to insert key into
AP.RecNo = RecNo2Use 'associate this record number with key
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
stat = BULLET(AP)
IF stat = 0 THEN
'key added
ELSEIF stat = 201 THEN
'key already exists, which means you need to construct a unique enumerator--
'provided the file wasn't created for UNIQUE keys...INSTEAD USE InsertXB!
See: DeleteKeyXBsrc InsertXB
~DeleteKeyXBsrc
Func: DeleteKeyXB Pack: AccessPack Func: 46/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
TempStr = KeyToDelete$ + CHR$(0) 'delete the key from a UNIQUE index file
'(else need to supply enumerator also)
AP.Func = %DeleteKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file of key to delete
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(this key is searched for exactly)
stat = BULLET(AP) 'if exact match found the key is deleted!
IF stat = 0 THEN
'key deleted permanently
ELSEIF stat = 200 THEN
'key as stated was not in the index file--if the index is not UNQIUE then
'you must supply the exact enumerator along with the key proper to delete
'--you can use the CurrentKeyXB routine to obtain the exact current key
'other error
See: BuildKeyXBsrc
~BuildKeyXBsrc
Func: BuildKeyXB Pack: AccessPack Func: 47/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
'Assume record has been built and is ready to be added to the data file. The
'record is in the variable RecBuff (a fixed-length TYPE variable, typically).
AP.Func = %BuildKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file key is to be built for
AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to data record buffer
AP.RecPtrSeg = VARSEG(RecBuff)
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the built key is put here)
stat = BULLET(AP)
IF stat = 0 THEN
'key built okay so can do a AddRecordXB followed by a StoreKeyXB
'but, again, InsertXB takes care of all this detail and then some--use it
'error
See: CurrentKeyXBsrc
~CurrentKeyXBsrc
Func: CurrentKeyXB Pack: AccessPack Func: 48/Mid-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
AP.Func = %CurrentKeyXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the current key is put here)
stat = BULLET(AP)
IF stat = 0 THEN
'TempStr set to current key (valid only for KeyLen bytes)
'Also, AP.RecNo is set to the record number of the key.
'error
See: GetFirstXBsrc
~GetFirstXBsrc
Func: GetFirstXB Pack: AccessPack Func: 60/High-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
AP.Func = %GetFirstXB 'defined in PBULLET.BI
AP.Handle = indexhandle 'handle to index file to access key from
AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the first key is read from disk and put here)
stat = BULLET(AP)
IF stat = 0 THEN
'TempStr is filled in with the key (for as many bytes as the key length)
'RecBuff is filled in with the data record
'AP.RecNo is set to the record number of the first key in the index.
'error
See: GetEqualXBsrc
~GetEqualXBsrc
Func: GetEqualXB Pack: AccessPack Func: 61/High-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
'passed key to find, start with enum=0
TempStr = FindKey$ + CHR$(0) + CHR$(0) + CHR$(0) '2 enumerator bytes + 0-term
AP.Func = %GetEqualXB 'defined in PBULLET.BI
AP.Handle = indexfile 'handle to index file to find key from
AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr)
stat = BULLET(AP)
IF stat = 0 THEN
'RecBuff, and AP.RecNo filled as expected (TempStr remains the same)
ELSEIF stat = 200 THEN
AP.Func = %GetNextXB 'if not found, can get following key--the next
stat = BULLET(AP) 'key would logically follow the key not found
'--this let's you search based on partial keys
See: GetNextXBsrc
~GetNextXBsrc
Func: GetNextXB Pack: AccessPack Func: 62/High-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
AP.Func = %GetFirstXB 'defined in PBULLET.BI
AP.Handle = indexhandle 'handle to index file to access key from
AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the first key is read from disk and put here)
stat = BULLET(AP)
DO WHILE stat = 0 'print all records in key order
PRINT AP.RecNo; RecBuff.code; ", "; RecBuff.bday
AP.Func = %GetNextXB
stat = BULLET(AP)
IF stat <> 202 THEN 'error 202 means end of file (expected)
'error other than expected EOF
See: GetPrevXBsrc
~GetPrevXBsrc
Func: GetPrevXB Pack: AccessPack Func: 63/High-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
AP.Func = %GetLastXB 'defined in PBULLET.BI
AP.Handle = indexhandle 'handle to index file to access key from
AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
stat = BULLET(AP)
DO WHILE stat = 0 'print all records in REVERSE key order
PRINT AP.RecNo; RecBuff.code; ", "; RecBuff.bday
AP.Func = %GetPrevXB
stat = BULLET(AP)
IF stat <> 203 THEN 'error 203 means top of file (expected)
'error other than expected TOF
See: GetLastXBsrc
~GetLastXBsrc
Func: GetLastXB Pack: AccessPack Func: 64/High-level
DIM AP AS AccessPack
DIM TempStr AS STRING * 64 'used as fixed-length string for VARPTR()
DIM RecBuff AS RecordTYPE 'see AddRecordXBsrc for record layout
AP.Func = %GetLastXB 'defined in PBULLET.BI
AP.Handle = indexhandle 'handle to index file to access key from
AP.RecPtrOff = VARPTR(RecBuff) 'far pointer to record buffer
AP.RecPtrSeg = VARSEG(RecBuff) '(the record indexed by the key is put here)
AP.KeyPtrOff = VARPTR(TempStr) 'far pointer to key buffer
AP.KeyPtrSeg = VARSEG(TempStr) '(the last key is read from disk and put here)
stat = BULLET(AP)
IF stat = 0 THEN
'TempStr is filled in with the key (for as many bytes as the key length)
'RecBuff is filled in with the data record
'AP.RecNo is set to the record number of the last key in the index.
'error
See: InsertXBsrc
~InsertXBsrc
Func: InsertXB Pack: AccessPack Func: 65/High-level
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'TempStr and RecBuff previously defined
FOR i = 1 TO 3 '3=number of related indexes to maintain
AP(i).Func = %InsertXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).RecPtrOff = VARPTR(RecBuff)
AP(i).RecPtrSeg = VARSEG(RecBuff)
see AddRecordXBsrc for RecBuff TYPE
AP(i).KeyPtrOff = VARPTR(TempStr)
(be sure you reserved the tag field)
AP(i).KeyPtrSeg = VARSEG(TempStr)
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1)) 'AP(1 TO 4) to avoid subscript error
AP(3).NextPtrOff = 0 'reset last access pack to end-link value
AP(3).NextPtrSeg = 0
stat = BULLET(AP(1))
IF stat = 0 THEN 'if stat=0 must still check AP(1).Stat
IF AP(1).Stat <> 0 THEN 'error when adding data record
TrueError = AP(stat).Stat 'the returned stat is array index of bad pack
See: UpdateXBsrc
~UpdateXBsrc
Func: UpdateXB Pack: AccessPack Func: 66/High-level
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'TempStr and RecBuff previously defined
FOR i = 1 TO 3 '3=number of related indexes to maintain
AP(i).Func = %UpdateXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).RecNo = RecordNumberToUpdate& 'tell it which record to update
AP(i).RecPtrOff = VARPTR(RecBuff) 'RecBuff has new, updated data
AP(i).RecPtrSeg = VARSEG(RecBuff)
AP(i).KeyPtrOff = VARPTR(TempStr)
AP(i).KeyPtrSeg = VARSEG(TempStr)
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1)) 'AP(1 TO 4) to avoid subscript error
AP(3).NextPtrOff = 0 : AP(3).NextPtrSeg = 0 'reset last access pack to 0
stat = BULLET(AP(1))
IF stat = 0 THEN 'if stat=0 must still check AP(1).Stat
IF AP(1).Stat <> 0 THEN 'error when writing data record
TrueError = AP(stat).Stat 'the returned stat is array index of bad pack
See: ReindexXBsrc
~ReindexXBsrc
Func: ReindexXB Pack: AccessPack Func: 67/High-level
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'DIM'd to 4 to avoid bad subscript in loop
FOR i = 1 TO 3 '3=number of related indexes to reindex
AP(i).Func = %ReindexXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1)) 'AP(1 TO 4) to avoid subscript error
AP(3).NextPtrOff = 0
AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
stat = BULLET(AP(1))
IF stat THEN 'if stat <> 0 then the...
TrueError = AP(stat).Stat '...returned stat is array index of bad pack
The reason AP() is REDIM AP(1 TO 4) is so that the AP(i + 1) in the code loop
doesn't create an invalid subscript error.
See: LockXBsrc
~LockXBsrc
Func: LockXB Pack: AccessPack Func: 80/Network
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'DIM'd to 4 to avoid bad subscript in loop
FOR i = 1 TO 3 '3=number of related indexes to Lock
AP(i).Func = %LockXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1))
NEXT 'data file handle known internally by BULLET
AP(3).NextPtrOff = 0
AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
stat = BULLET(AP(1))
IF stat > 3 THEN 'if stat > 3 (> number of packs) then the...
TrueError = AP(3).Stat '...lock failed on the data file
ELSEIF stat <> 0 THEN (|last ReadKHXB)
TrueError = AP(stat).Stat '...lock failed on index file # stat
The Lock routines use a different method to identify the bad pack when the
failure was caused by the data file. See above.
See: UnlockXBsrc
~UnlockXBsrc
Func: UnlockXB Pack: AccessPack Func: 81/Network
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'DIM'd to 4 to avoid bad subscript in loop
FOR i = 1 TO 3 '3=number of related indexes to Lock
AP(i).Func = %UnlockXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1))
NEXT 'data file handle known internally by BULLET
AP(3).NextPtrOff = 0
AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
stat = BULLET(AP(1))
IF stat > 3 THEN 'if stat > 3 (> number of packs) then the...
TrueError = AP(3).Stat '...unlock failed on the data file
ELSEIF stat <> 0 THEN
TrueError = AP(stat).Stat '...unlock failed on index file # stat
The Lock routines use a different method to identify the bad pack when the
failure was caused by the data file. See above.
See: LockKeyXBsrc
~LockKeyXBsrc
Func: LockKeyXB Pack: AccessPack Func: 82/Network
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'DIM'd to 4 to avoid bad subscript in loop
FOR i = 1 TO 3 '3=number of related indexes to Lock
AP(i).Func = %LockXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1))
AP(3).NextPtrOff = 0
AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
stat = BULLET(AP(1))
IF stat <> 0 THEN
TrueError = AP(stat).Stat 'lock failed on index file # stat
'--if stat > 3 then failed on last internal
'--ReadKHXB...This is EXTREMELY unlikely
See: UnlockKeyXBsrc
~UnlockKeyXBsrc
Func: UnlockKeyXB Pack: AccessPack Func: 83/Network
REDIM AP(1 TO 4) AS AccessPack 'array of 3 access packs, 1 for each index file
'DIM'd to 4 to avoid bad subscript in loop
FOR i = 1 TO 3 '3=number of related indexes to Lock
AP(i).Func = %UnlockKeyXB
AP(i).Handle = indexhandle(i) 'each index file's handle
AP(i).NextPtrOff = VARPTR(AP(i + 1)) 'point to NEXT access pack
AP(i).NextPtrSeg = VARSEG(AP(i + 1))
AP(3).NextPtrOff = 0
AP(3).NextPtrSeg = 0 'reset last access pack to end-link value
stat = BULLET(AP(1))
IF stat <> 0 THEN
TrueError = AP(stat).Stat 'unlock failed on index file # stat
See: LockDataXBsrc
~LockDataXBsrc
Func: LockDataXB Pack: AccessPack Func: 84/Network
DIM AP AS AccessPack
AP.Func = %LockDataXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle of data file to lock
AP.RecNo = 0& '=0 to lock all or, set to actual record number
stat = BULLET(AP) ' to lock as in AP.RecNo = lockThisRec&
IF stat THEN 'error
See: UnlockDataXBsrc
~UnlockDataXBsrc
Func: UnlockDataXB Pack: AccessPack Func: 85/Network
DIM AP AS AccessPack
AP.Func = %UnlockDataXB 'defined in PBULLET.BI
AP.Handle = datahandle 'handle of data file to unlock
AP.RecNo = 0& '=0 to unlock all or, set to actual record num
stat = BULLET(AP) ' to unlock as in AP.RecNo = lockThisRec&
IF stat THEN 'error
'note: you cannot unlock parts of a file with
'1 single unlock (where AP.RecNo=0). Instead,
'you must unlock each record individually--
'that is, if you made any single-record locks
See: DriveRemoteXBsrc
~DriveRemoteXBsrc
Func: DriveRemoteXB Pack: RemotePack Func: 86/Network
DIM RP AS RemotePack
RP.Func = %DriveRemoteXB 'defined in PBULLET.BI
RP.Handle = drive2check 'drive to check (0=default, 1=A:,2=B:,3=C:...)
stat = BULLET(RP)
IF stat = 0 THEN
'RP.IsRemote set to 0 if drive local, 1 if remote
'RP.Flags set to DX register as returned by DOS
'RP.IsShare set to 0 if SHARE.EXE is not loaded, non-zero SHARE installed
'error (like invalid drive)
See: FileRemoteXBsrc
~FileRemoteXBsrc
Func: FileRemoteXB Pack: RemotePack Func: 87/Network
DIM RP AS RemotePack
RP.Func = %FileRemoteXB 'defined in PBULLET.BI
RP.Handle = filehandle 'file handle to check
stat = BULLET(RP)
IF stat = 0 THEN
'RP.IsRemote set to 0 if file local, 1 if remote
'RP.Flags set to DX register as returned by DOS
'RP.IsShare set to 0 if SHARE.EXE is not loaded, non-zero SHARE installed
'error (like invalid handle)
See: SetRetriesXBsrc
~SetRetriesXBsrc
Func: SetRetriesXB Pack: SetRetriesPack Func: 88/Network
DIM SRP AS SetRetriesPack
SRP.Func = %SetRetriesXB
SRP.Mode = 1 '1=set to user values, 0=set DOS default
SRP.Pause = 5000 'do 5,000 loops between retries
SRP.Retries = 5 'try 5 times before giving up with error
stat = BULLET(SRP)
IF stat THEN
'error 'it's unlikely an error occurs
See: DeleteFileDOSsrc
~DeleteFileDOSsrc
Func: DeleteFileDOS Pack: DOSFilePack Func: 100/DOS
DIM DFP AS DOSFilePack
DIM TempStr AS STRING * 80
TempStr = file2delete$ + CHR$(0)
DFP.Func = %DeleteFileDOS 'defined in PBULLET.BI
DFP.FilenamePtrOff = VARPTR(TempStr)
DFP.FilenamePtrSeg = VARSEG(TempStr)
stat = BULLET(DFP)
IF stat THEN 'error
See: RenameFileDOSsrc
~RenameFileDOSsrc
Func: RenameFileDOS Pack: DOSFilePack Func: 101/DOS
DIM DFP AS DOSFilePack
DIM TempStr AS STRING * 80
DIM TempStr2 AS STRING * 80
TempStr = file2rename$ + CHR$(0)
TempStr2 = newfilename$ + CHR$(0)
DFP.Func = %RenameFileDOS 'defined in PBULLET.BI
DFP.FilenamePtrOff = VARPTR(TempStr)
DFP.FilenamePtrSeg = VARSEG(TempStr)
DFP.NewNamePtrOff = VARPTR(TempStr2)
DFP.NewNamePtrSeg = VARSEG(TempStr2)
stat = BULLET(DFP)
IF stat THEN 'error
See: CreateFileDOSsrc
~CreateFileDOSsrc
Func: CreateFileDOS Pack: DOSFilePack Func: 102/DOS
DIM DFP AS DOSFilePack
DIM TempStr AS STRING * 80
TempStr = file2create$ + CHR$(0)
DFP.Func = %CreateFileDOS 'defined in PBULLET.BI
DFP.FilenamePtrOff = VARPTR(TempStr)
DFP.FilenamePtrSeg = VARSEG(TempStr)
DFP.Attr = 0 'normal file directory attribute
stat = BULLET(DFP)
IF stat THEN 'error
See: AccessFileDOSsrc
~AccessFileDOSsrc
Func: AccessFileDOS Pack: DOSFilePack Func: 103/DOS
DIM DFP AS DOSFilePack
DIM TempStr AS STRING * 80
TempStr = file2access$ + CHR$(0)
DFP.Func = %AccessFileDOS 'defined in PBULLET.BI
DFP.FilenamePtrOff = VARPTR(TempStr)
DFP.FilenamePtrSeg = VARSEG(TempStr)
DFP.ASmode = &H42 'attempt R/W DENY NONE access
stat = BULLET(DFP)
IF stat THEN 'error
See: OpenFileDOSsrc
~OpenFileDOSsrc
Func: OpenFileDOS Pack: DOSFilePack Func: 104/DOS
DIM DFP AS DOSFilePack
DIM TempStr AS STRING * 80
TempStr = file2open$ + CHR$(0)
DFP.Func = %OpenFileDOS 'defined in PBULLET.BI
DFP.FilenamePtrOff = VARPTR(TempStr)
DFP.FilenamePtrSeg = VARSEG(TempStr)
DFP.ASmode = &H42 'open in R/W DENY NONE access
stat = BULLET(DFP)
IF stat = 0 THEN
'DFP.Handle set to handle of open file
'error
See: SeekFileDOSsrc
~SeekFileDOSsrc
Func: SeekFileDOS Pack: DOSFilePack Func: 105/DOS
DIM DFP AS DOSFilePack
DFP.Func = %SeekFileDOS 'defined in PBULLET.BI
DFP.Handle = handle
DFP.SeekOffset = 0& 'position 0 relative EOF (get length of file)
DFP.Method = 2 'seek from END of file
stat = BULLET(DFP)
IF stat = 0 THEN
'DFP.SeekOffset set to absolute current offset
'--in this case, the DFP.SeekOffset equals then length of the file
'error
See: ReadFileDOSsrc
~ReadFileDOSsrc
Func: ReadFileDOS Pack: DOSFilePack Func: 106/DOS
DIM DFP AS DOSFilePack
DIM ReadBuff AS STRING * 512 'sector buffer
DFP.Func = %ReadFileDOS 'defined in PBULLET.BI
DFP.Handle = handle
DFP.Bytes = Bytes2Read '16-bit value, in this case 512 since that's
DFP.BufferPtrOff = VARPTR(ReadBuff) 'the size of ReadBuff
DFP.BufferPtrSeg = VARSEG(ReadBuff)
stat = BULLET(DFP)
IF stat = 0 THEN
IF DFP.Bytes <> Bytes2Read THEN 'check if EOF processed
'hit EOF before reading all 512 bytes
ELSE
'ReadBuff filled with 512 bytes of data read from the current disk pos
'disk position moved to the last byte read + 1
ENDIF
'error
See: ExpandFileDOSsrc
~ExpandFileDOSsrc
Func: ExpandFileDOS Pack: DOSFilePack Func: 107/DOS
DIM DFP AS DOSFilePack
DFP.Func = % ExpandFileDOS 'defined in PBULLET.BI
DFP.Handle = handle
DFP.SeekOffset = Bytes2ExpandBy&
stat = BULLET(DFP)
IF stat = 0 THEN
'file expanded by number of bytes specified
'error
See: WriteFileDOSsrc
~WriteFileDOSsrc
Func: WriteFileDOS Pack: DOSFilePack Func: 108/DOS
DIM DFP AS DOSFilePack
DIM WriteBuff AS STRING * 512 'sector buffer
DFP.Func = %WriteFileDOS 'defined in PBULLET.BI
DFP.Handle = handle
DFP.Bytes = Bytes2Write '16-bit value, in this case 512 since that's
DFP.BufferPtrOff = VARPTR(WriteBuff) 'the size of WriteBuff
DFP.BufferPtrSeg = VARSEG(WriteBuff)
stat = BULLET(DFP)
IF stat = -2 THEN
'disk full
ELSE IF stat THEN
'other error
'okay
Unlike ReadFileDOS, if the number of bytes actually written does not equal
Bytes2Write, the WriteFileDOS routine returns a DISK FULL error code (-2).
See: CloseFileDOSsrc
~CloseFileDOSsrc
Func: CloseFileDOS Pack: DOSFilePack Func: 109/DOS
DIM DFP AS DOSFilePack
DFP.Func = %CloseFileDOS 'defined in PBULLET.BI
DFP.Handle =handle2close
stat = BULLET(DFP)
IF stat THEN 'error
See: MakeDirDOSsrc
~MakeDirDOSsrc
Func: MakeDirDOS Pack: DOSFilePack Func: 110/DOS
DIM DFP AS DOSFilePack
DIM TempStr AS STRING * 80
TempStr = subdir2make$ + CHR$(0)
DFP.Func = %MakeDirDOS 'defined in PBULLET.BI
DFP.FilenamePtrOff = VARPTR(TempStr)
DFP.FilenamePtrSeg = VARSEG(TempStr)
stat = BULLET(DFP)
IF stat THEN 'error
See: DeleteFileDOSsrc